<commit_before>package main

import (
	"crypto/tls"
)

func main() {}

func minMaxTlsVersion() {
	{
		config := &tls.Config{}
		config.MinVersion = 0 // BAD
	}
	{
		config := &tls.Config{}
		config.MaxVersion = 0 // GOOD
	}
	///
	{
		config := &tls.Config{
			MinVersion: 0, // BAD
		}
		_ = config
	}
	{
		config := &tls.Config{
			MaxVersion: 0, // GOOD
		}
		_ = config
	}
	///
	{
		config := &tls.Config{}
		config.MinVersion = tls.VersionSSL30 // BAD
	}
	{
		config := &tls.Config{}
		config.MaxVersion = tls.VersionSSL30 // BAD
	}
	///
	{
		config := &tls.Config{}
		config.MinVersion = tls.VersionTLS10 // BAD
	}
	{
		config := &tls.Config{}
		config.MaxVersion = tls.VersionTLS10 // BAD
	}
	///
	{
		config := &tls.Config{}
		config.MinVersion = tls.VersionTLS11 // BAD
	}
	{
		config := &tls.Config{}
		config.MaxVersion = tls.VersionTLS11 // BAD
	}
	///
	{
		config := &tls.Config{
			MinVersion: tls.VersionTLS11, // BAD
		}
		_ = config
	}
	{
		config := &tls.Config{
			MaxVersion: tls.VersionTLS11, // BAD
		}
		_ = config
	}
	{
		config := &tls.Config{
			MinVersion: tls.VersionTLS12, // GOOD
		}
		_ = config
	}
	{
		config := &tls.Config{
			MaxVersion: tls.VersionTLS13, // GOOD
		}
		_ = config
	}
	///
	{
		config := &tls.Config{
			MinVersion: 0x0300, // BAD
		}
		_ = config
	}
	{
		config := &tls.Config{
			MaxVersion: 0x0301, // BAD
		}
		_ = config
	}
}

func cipherSuites() {
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_RSA_WITH_RC4_128_SHA,                // BAD
				tls.TLS_RSA_WITH_AES_128_CBC_SHA256,         // BAD
				tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,        // BAD
				tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,          // BAD
				tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // BAD
				tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,   // BAD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_RSA_WITH_RC4_128_SHA, // BAD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_RSA_WITH_AES_128_CBC_SHA256, // BAD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, // BAD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, // BAD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // BAD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, // BAD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_CHACHA20_POLY1305_SHA256, // GOOD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{}
		config.CipherSuites = make([]uint16, 0)
		config.CipherSuites = append(config.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) // BAD
	}
	{
		config := &tls.Config{}
		config.CipherSuites = make([]uint16, 0)
		insecureSuites := tls.InsecureCipherSuites()
		for _, v := range insecureSuites {
			config.CipherSuites = append(config.CipherSuites, v.ID) // BAD
		}
	}
	{
		config := &tls.Config{}
		cipherSuites := make([]uint16, 0)
		insecureSuites := tls.InsecureCipherSuites()
		for _, v := range insecureSuites {
			cipherSuites = append(cipherSuites, v.ID)
		}
		config.CipherSuites = cipherSuites // BAD
	}
	{
		config := &tls.Config{}
		cipherSuites := make([]uint16, 0)
		insecureSuites := tls.InsecureCipherSuites()
		for i := range insecureSuites {
			cipherSuites = append(cipherSuites, insecureSuites[i].ID)
		}
		config.CipherSuites = cipherSuites // BAD
	}
}

func good(version string) {
	config := &tls.Config{}

	switch version {
	case "1.0":
		config.MinVersion = tls.VersionTLS10 // OK
		config.MaxVersion = tls.VersionTLS11 // BAD
	case "1.1":
		config.MinVersion = tls.VersionTLS11 // OK
	default:
		config.MinVersion = tls.VersionTLS12 // OK
	}

	_ = config
}
func badTlsVersion2(version string) {
	{
		config := &tls.Config{}

		switch version {
		case "1.0":
			config.MinVersion = tls.VersionTLS10 // OK
		case "1.1":
			config.MinVersion = tls.VersionTLS11 // OK
		default:
			config.MinVersion = tls.VersionTLS12 // OK
		}

		config.MinVersion = tls.VersionTLS11 // BAD

		_ = config
	}
	{

		switch version {
		case "1.0":
			config := &tls.Config{}
			config.MinVersion = tls.VersionTLS10 // BAD
			config.MinVersion = tls.VersionTLS11 // BAD
			_ = config
		}

	}
}
<commit_msg>Fix comment<commit_after>package main

import (
	"crypto/tls"
)

func main() {}

func minMaxTlsVersion() {
	{
		config := &tls.Config{}
		config.MinVersion = 0 // BAD
	}
	{
		config := &tls.Config{}
		config.MaxVersion = 0 // GOOD
	}
	///
	{
		config := &tls.Config{
			MinVersion: 0, // BAD
		}
		_ = config
	}
	{
		config := &tls.Config{
			MaxVersion: 0, // GOOD
		}
		_ = config
	}
	///
	{
		config := &tls.Config{}
		config.MinVersion = tls.VersionSSL30 // BAD
	}
	{
		config := &tls.Config{}
		config.MaxVersion = tls.VersionSSL30 // BAD
	}
	///
	{
		config := &tls.Config{}
		config.MinVersion = tls.VersionTLS10 // BAD
	}
	{
		config := &tls.Config{}
		config.MaxVersion = tls.VersionTLS10 // BAD
	}
	///
	{
		config := &tls.Config{}
		config.MinVersion = tls.VersionTLS11 // BAD
	}
	{
		config := &tls.Config{}
		config.MaxVersion = tls.VersionTLS11 // BAD
	}
	///
	{
		config := &tls.Config{
			MinVersion: tls.VersionTLS11, // BAD
		}
		_ = config
	}
	{
		config := &tls.Config{
			MaxVersion: tls.VersionTLS11, // BAD
		}
		_ = config
	}
	{
		config := &tls.Config{
			MinVersion: tls.VersionTLS12, // GOOD
		}
		_ = config
	}
	{
		config := &tls.Config{
			MaxVersion: tls.VersionTLS13, // GOOD
		}
		_ = config
	}
	///
	{
		config := &tls.Config{
			MinVersion: 0x0300, // BAD
		}
		_ = config
	}
	{
		config := &tls.Config{
			MaxVersion: 0x0301, // BAD
		}
		_ = config
	}
}

func cipherSuites() {
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_RSA_WITH_RC4_128_SHA,                // BAD
				tls.TLS_RSA_WITH_AES_128_CBC_SHA256,         // BAD
				tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,        // BAD
				tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,          // BAD
				tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // BAD
				tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,   // BAD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_RSA_WITH_RC4_128_SHA, // BAD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_RSA_WITH_AES_128_CBC_SHA256, // BAD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, // BAD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, // BAD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // BAD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, // BAD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{
			CipherSuites: []uint16{
				tls.TLS_CHACHA20_POLY1305_SHA256, // GOOD
			},
		}
		_ = config
	}
	{
		config := &tls.Config{}
		config.CipherSuites = make([]uint16, 0)
		config.CipherSuites = append(config.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) // BAD
	}
	{
		config := &tls.Config{}
		config.CipherSuites = make([]uint16, 0)
		insecureSuites := tls.InsecureCipherSuites()
		for _, v := range insecureSuites {
			config.CipherSuites = append(config.CipherSuites, v.ID) // BAD
		}
	}
	{
		config := &tls.Config{}
		cipherSuites := make([]uint16, 0)
		insecureSuites := tls.InsecureCipherSuites()
		for _, v := range insecureSuites {
			cipherSuites = append(cipherSuites, v.ID)
		}
		config.CipherSuites = cipherSuites // BAD
	}
	{
		config := &tls.Config{}
		cipherSuites := make([]uint16, 0)
		insecureSuites := tls.InsecureCipherSuites()
		for i := range insecureSuites {
			cipherSuites = append(cipherSuites, insecureSuites[i].ID)
		}
		config.CipherSuites = cipherSuites // BAD
	}
}

func good(version string) {
	config := &tls.Config{}

	switch version {
	case "1.0":
		config.MinVersion = tls.VersionTLS10 // OK
		config.MaxVersion = tls.VersionTLS11 // OK
	case "1.1":
		config.MinVersion = tls.VersionTLS11 // OK
	default:
		config.MinVersion = tls.VersionTLS12 // OK
	}

	_ = config
}
func badTlsVersion2(version string) {
	{
		config := &tls.Config{}

		switch version {
		case "1.0":
			config.MinVersion = tls.VersionTLS10 // OK
		case "1.1":
			config.MinVersion = tls.VersionTLS11 // OK
		default:
			config.MinVersion = tls.VersionTLS12 // OK
		}

		config.MinVersion = tls.VersionTLS11 // BAD

		_ = config
	}
	{

		switch version {
		case "1.0":
			config := &tls.Config{}
			config.MinVersion = tls.VersionTLS10 // BAD
			config.MinVersion = tls.VersionTLS11 // BAD
			_ = config
		}

	}
}
<|endoftext|>


<commit_before>package miner

import (
	"errors"
	"sync"
	"time"

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/persist"
	"github.com/NebulousLabs/Sia/types"
)

const (
	// HeaderMemory is the number of previous calls to 'header'
	// that are remembered. Additionally, 'header' will only poll for a
	// new block every 'headerMemory / blockMemory' times it is
	// called. This reduces the amount of memory used, but comes at the cost of
	// not always having the most recent transactions.
	HeaderMemory = 10000

	// BlockMemory is the maximum number of blocks the miner will store
	// Blocks take up to 2 megabytes of memory, which is why this number is
	// limited.
	BlockMemory = 50

	// MaxSourceBlockAge is the maximum amount of time that is allowed to
	// elapse between generating source blocks.
	MaxSourceBlockAge = 60 * time.Second
)

var (
	errNilCS     = errors.New("miner cannot use a nil consensus set")
	errNilTpool  = errors.New("miner cannot use a nil transaction pool")
	errNilWallet = errors.New("miner cannot use a nil wallet")
)

// Miner struct contains all variables the miner needs
// in order to create and submit blocks.
type Miner struct {
	// Module dependencies.
	cs     modules.ConsensusSet
	tpool  modules.TransactionPool
	wallet modules.Wallet

	// BlockManager variables. Becaues blocks are large, one block is used to
	// make many headers which can be used by miners. Headers include an
	// arbitrary data transaction (appended to the block) to make the merkle
	// roots unique (preventing miners from doing redundant work). Every N
	// requests or M seconds, a new block is used to create headers.
	//
	// Only 'blocksMemory' blocks are kept in memory at a time, which
	// keeps ram usage reasonable. Miners may request many headers in parallel,
	// and thus may be working on different blocks. When they submit the solved
	// header to the block manager, the rest of the block needs to be found in
	// a lookup.
	blockMem        map[types.BlockHeader]*types.Block             // Mappings from headers to the blocks they are derived from.
	arbDataMem      map[types.BlockHeader][crypto.EntropySize]byte // Mappings from the headers to their unique arb data.
	headerMem       []types.BlockHeader                            // A circular list of headers that have been given out from the api recently.
	sourceBlock     *types.Block                                   // The block from which new headers for mining are created.
	sourceBlockTime time.Time                                      // How long headers have been using the same block (different from 'recent block').
	memProgress     int                                            // The index of the most recent header used in headerMem.

	// CPUMiner variables.
	miningOn bool  // indicates if the miner is supposed to be running
	mining   bool  // indicates if the miner is actually running
	hashRate int64 // indicates hashes per second

	// Utils
	persistDir string
	persist    persistence
	log        *persist.FileLogger
	mu         sync.RWMutex
}

// newHandleErrInvalidConsensusChangeID manages the rescanning in the event
// that a subscription during startup fails.
func (m *Miner) newHandleErrInvalidConsensusChangeID() error {
	// If the change id is not recognized, it means that the consensus set
	// has somehow reset or otherwise changed, and a rescan must be
	// performed.
	m.log.Println("Inconsistency found between the miner and the consensus set, fixing...")

	// Perform the rescan and block until rescanning is complete. Rescan
	// does need access to a lock, but no lock is held during startup
	// anyway, so blocking until the channel returns an error is safe.
	c := make(chan error, 1)
	m.threadedConsensusRescan(c)
	return <-c
}

// New returns a ready-to-go miner that is not mining.
func New(cs modules.ConsensusSet, tpool modules.TransactionPool, w modules.Wallet, persistDir string) (*Miner, error) {
	// Create the miner and its dependencies.
	if cs == nil {
		return nil, errNilCS
	}
	if tpool == nil {
		return nil, errNilTpool
	}
	if w == nil {
		return nil, errNilWallet
	}

	// Assemble the miner. The miner is assembled without an address because
	// the wallet is likely not unlocked yet. The miner will grab an address
	// after the miner is unlocked (this must be coded manually for each
	// function that potentially requires the miner to have an address.
	m := &Miner{
		cs:     cs,
		tpool:  tpool,
		wallet: w,

		blockMem:   make(map[types.BlockHeader]*types.Block),
		arbDataMem: make(map[types.BlockHeader][crypto.EntropySize]byte),
		headerMem:  make([]types.BlockHeader, HeaderMemory),

		persistDir: persistDir,
	}

	err := m.initPersist()
	if err != nil {
		return nil, errors.New("miner persistence startup failed: " + err.Error())
	}

	err = m.cs.ConsensusSetPersistentSubscribe(m, m.persist.RecentChange)
	if err == modules.ErrInvalidConsensusChangeID {
		err = m.newHandleErrInvalidConsensusChangeID()
		if err != nil {
			return nil, errors.New("miner startup failed - rescanning failed: " + err.Error())
		}
	} else if err != nil {
		return nil, errors.New("miner subscription failed: " + err.Error())
	}

	m.tpool.TransactionPoolSubscribe(m)
	return m, nil
}

// Close terminates all ongoing processes involving the miner, enabling garbage
// collection.
func (m *Miner) Close() error {
	m.cs.Unsubscribe(m)
	return m.log.Close()
}

// checkAddress checks that the miner has an address, fetching an address from
// the wallet if not.
func (m *Miner) checkAddress() error {
	if m.persist.Address != (types.UnlockHash{}) {
		return nil
	}
	uc, err := m.wallet.NextAddress()
	if err != nil {
		return err
	}
	m.persist.Address = uc.UnlockHash()
	return nil
}

// BlocksMined returns the number of good blocks and stale blocks that have
// been mined by the miner.
func (m *Miner) BlocksMined() (goodBlocks, staleBlocks int) {
	m.mu.Lock()
	defer m.mu.Unlock()

	for _, blockID := range m.persist.BlocksFound {
		if m.cs.InCurrentPath(blockID) {
			goodBlocks++
		} else {
			staleBlocks++
		}
	}
	return
}
<commit_msg>switch to more pedantic use of 'threadedConsensusRescan'<commit_after>package miner

import (
	"errors"
	"sync"
	"time"

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/persist"
	"github.com/NebulousLabs/Sia/types"
)

const (
	// HeaderMemory is the number of previous calls to 'header'
	// that are remembered. Additionally, 'header' will only poll for a
	// new block every 'headerMemory / blockMemory' times it is
	// called. This reduces the amount of memory used, but comes at the cost of
	// not always having the most recent transactions.
	HeaderMemory = 10000

	// BlockMemory is the maximum number of blocks the miner will store
	// Blocks take up to 2 megabytes of memory, which is why this number is
	// limited.
	BlockMemory = 50

	// MaxSourceBlockAge is the maximum amount of time that is allowed to
	// elapse between generating source blocks.
	MaxSourceBlockAge = 60 * time.Second
)

var (
	errNilCS     = errors.New("miner cannot use a nil consensus set")
	errNilTpool  = errors.New("miner cannot use a nil transaction pool")
	errNilWallet = errors.New("miner cannot use a nil wallet")
)

// Miner struct contains all variables the miner needs
// in order to create and submit blocks.
type Miner struct {
	// Module dependencies.
	cs     modules.ConsensusSet
	tpool  modules.TransactionPool
	wallet modules.Wallet

	// BlockManager variables. Becaues blocks are large, one block is used to
	// make many headers which can be used by miners. Headers include an
	// arbitrary data transaction (appended to the block) to make the merkle
	// roots unique (preventing miners from doing redundant work). Every N
	// requests or M seconds, a new block is used to create headers.
	//
	// Only 'blocksMemory' blocks are kept in memory at a time, which
	// keeps ram usage reasonable. Miners may request many headers in parallel,
	// and thus may be working on different blocks. When they submit the solved
	// header to the block manager, the rest of the block needs to be found in
	// a lookup.
	blockMem        map[types.BlockHeader]*types.Block             // Mappings from headers to the blocks they are derived from.
	arbDataMem      map[types.BlockHeader][crypto.EntropySize]byte // Mappings from the headers to their unique arb data.
	headerMem       []types.BlockHeader                            // A circular list of headers that have been given out from the api recently.
	sourceBlock     *types.Block                                   // The block from which new headers for mining are created.
	sourceBlockTime time.Time                                      // How long headers have been using the same block (different from 'recent block').
	memProgress     int                                            // The index of the most recent header used in headerMem.

	// CPUMiner variables.
	miningOn bool  // indicates if the miner is supposed to be running
	mining   bool  // indicates if the miner is actually running
	hashRate int64 // indicates hashes per second

	// Utils
	persistDir string
	persist    persistence
	log        *persist.FileLogger
	mu         sync.RWMutex
}

// newHandleErrInvalidConsensusChangeID manages the rescanning in the event
// that a subscription during startup fails.
func (m *Miner) newHandleErrInvalidConsensusChangeID() error {
	// If the change id is not recognized, it means that the consensus set
	// has somehow reset or otherwise changed, and a rescan must be
	// performed.
	m.log.Println("Inconsistency found between the miner and the consensus set, fixing...")

	// Perform the rescan and block until rescanning is complete. Rescan
	// does need access to a lock, but no lock is held during startup
	// anyway, so blocking until the channel returns an error is safe.
	c := make(chan error)
	go m.threadedConsensusRescan(c)
	return <-c
}

// New returns a ready-to-go miner that is not mining.
func New(cs modules.ConsensusSet, tpool modules.TransactionPool, w modules.Wallet, persistDir string) (*Miner, error) {
	// Create the miner and its dependencies.
	if cs == nil {
		return nil, errNilCS
	}
	if tpool == nil {
		return nil, errNilTpool
	}
	if w == nil {
		return nil, errNilWallet
	}

	// Assemble the miner. The miner is assembled without an address because
	// the wallet is likely not unlocked yet. The miner will grab an address
	// after the miner is unlocked (this must be coded manually for each
	// function that potentially requires the miner to have an address.
	m := &Miner{
		cs:     cs,
		tpool:  tpool,
		wallet: w,

		blockMem:   make(map[types.BlockHeader]*types.Block),
		arbDataMem: make(map[types.BlockHeader][crypto.EntropySize]byte),
		headerMem:  make([]types.BlockHeader, HeaderMemory),

		persistDir: persistDir,
	}

	err := m.initPersist()
	if err != nil {
		return nil, errors.New("miner persistence startup failed: " + err.Error())
	}

	err = m.cs.ConsensusSetPersistentSubscribe(m, m.persist.RecentChange)
	if err == modules.ErrInvalidConsensusChangeID {
		err = m.newHandleErrInvalidConsensusChangeID()
		if err != nil {
			return nil, errors.New("miner startup failed - rescanning failed: " + err.Error())
		}
	} else if err != nil {
		return nil, errors.New("miner subscription failed: " + err.Error())
	}

	m.tpool.TransactionPoolSubscribe(m)
	return m, nil
}

// Close terminates all ongoing processes involving the miner, enabling garbage
// collection.
func (m *Miner) Close() error {
	m.cs.Unsubscribe(m)
	return m.log.Close()
}

// checkAddress checks that the miner has an address, fetching an address from
// the wallet if not.
func (m *Miner) checkAddress() error {
	if m.persist.Address != (types.UnlockHash{}) {
		return nil
	}
	uc, err := m.wallet.NextAddress()
	if err != nil {
		return err
	}
	m.persist.Address = uc.UnlockHash()
	return nil
}

// BlocksMined returns the number of good blocks and stale blocks that have
// been mined by the miner.
func (m *Miner) BlocksMined() (goodBlocks, staleBlocks int) {
	m.mu.Lock()
	defer m.mu.Unlock()

	for _, blockID := range m.persist.BlocksFound {
		if m.cs.InCurrentPath(blockID) {
			goodBlocks++
		} else {
			staleBlocks++
		}
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//     http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 engine

import (
	"errors"
	"fmt"
	"io"
	"math"
	"time"

	"github.com/aws/amazon-ecs-init/ecs-init/backoff"
	"github.com/aws/amazon-ecs-init/ecs-init/cache"
	"github.com/aws/amazon-ecs-init/ecs-init/config"
	"github.com/aws/amazon-ecs-init/ecs-init/docker"
	"github.com/aws/amazon-ecs-init/ecs-init/exec"
	"github.com/aws/amazon-ecs-init/ecs-init/exec/iptables"
	"github.com/aws/amazon-ecs-init/ecs-init/exec/sysctl"
	"github.com/aws/amazon-ecs-init/ecs-init/gpu"

	log "github.com/cihub/seelog"
)

const (
	terminalSuccessAgentExitCode  = 0
	containerFailureAgentExitCode = 2
	terminalFailureAgentExitCode  = 5
	upgradeAgentExitCode          = 42
	serviceStartMinRetryTime      = time.Millisecond * 500
	serviceStartMaxRetryTime      = time.Second * 15
	serviceStartRetryJitter       = 0.10
	serviceStartRetryMultiplier   = 2.0
	serviceStartMaxRetries        = math.MaxInt64 // essentially retry forever
	failedContainerLogWindowSize  = "200"         // as string for log config
)

// Engine contains methods invoked when ecs-init is run
type Engine struct {
	downloader               downloader
	docker                   dockerClient
	loopbackRouting          loopbackRouting
	credentialsProxyRoute    credentialsProxyRoute
	ipv6RouterAdvertisements ipv6RouterAdvertisements
	nvidiaGPUManager         gpu.GPUManager
}

// New creates an instance of Engine
func New() (*Engine, error) {
	downloader, err := cache.NewDownloader()
	if err != nil {
		return nil, err
	}
	docker, err := docker.NewClient()
	if err != nil {
		return nil, err
	}
	cmdExec := exec.NewExec()
	loopbackRouting, err := sysctl.NewIpv4RouteLocalNet(cmdExec)
	if err != nil {
		return nil, err
	}
	ipv6RouterAdvertisements, err := sysctl.NewIpv6RouterAdvertisements(cmdExec)
	if err != nil {
		return nil, err
	}
	credentialsProxyRoute, err := iptables.NewNetfilterRoute(cmdExec)
	if err != nil {
		return nil, err
	}
	return &Engine{
		downloader:               downloader,
		docker:                   docker,
		loopbackRouting:          loopbackRouting,
		credentialsProxyRoute:    credentialsProxyRoute,
		ipv6RouterAdvertisements: ipv6RouterAdvertisements,
		nvidiaGPUManager:         gpu.NewNvidiaGPUManager(),
	}, nil
}

// PreStart prepares the ECS Agent for starting. It also configures the instance
// to handle credentials requests from containers by rerouting these requests to
// to the ECS Agent's credentials endpoint
func (e *Engine) PreStart() error {
	// setup gpu if necessary
	err := e.PreStartGPU()
	if err != nil {
		return err
	}
	// Enable use of loopback addresses for local routing purposes
	err = e.loopbackRouting.Enable()
	if err != nil {
		return engineError("could not enable loopback routing", err)
	}
	// Disable ipv6 router advertisements
	err = e.ipv6RouterAdvertisements.Disable()
	if err != nil {
		return engineError("could not disable ipv6 router advertisements", err)
	}
	// Add the rerouting netfilter rule for credentials endpoint
	err = e.credentialsProxyRoute.Create()
	if err != nil {
		return engineError("could not create route to the credentials proxy", err)
	}

	imageLoaded, err := e.docker.IsAgentImageLoaded()
	if err != nil {
		return engineError("could not check Docker for Agent image presence", err)
	}

	switch e.downloader.AgentCacheStatus() {
	// Uncached, go get the Agent.
	case cache.StatusUncached:
		return e.downloadAndLoadCache()

	// The Agent is cached, and mandates a reload regardless of the
	// already loaded image.
	case cache.StatusReloadNeeded:
		return e.load(e.downloader.LoadCachedAgent())

	// Agent is cached, respect the already loaded Agent.
	case cache.StatusCached:
		if imageLoaded {
			return nil
		}
		return e.load(e.downloader.LoadCachedAgent())

	// There shouldn't be unhandled cache states.
	default:
		return errors.New("could not handle cache state")
	}
}

// PreStartGPU sets up the nvidia gpu manager if it's enabled.
func (e *Engine) PreStartGPU() error {
	envVariables := e.docker.LoadEnvVars()
	if val, ok := envVariables[config.GPUSupportEnvVar]; ok {
		if val == "true" {
			err := e.nvidiaGPUManager.Setup()
			if err != nil {
				log.Errorf("Nvidia GPU Manager: %v", err)
				return engineError("Nvidia GPU Manager", err)
			}
		}
	}
	return nil
}

// ReloadCache reloads the cached image of the ECS Agent into Docker
func (e *Engine) ReloadCache() error {
	cached := e.downloader.IsAgentCached()
	if !cached {
		return e.downloadAndLoadCache()
	}
	return e.load(e.downloader.LoadCachedAgent())
}

func (e *Engine) downloadAndLoadCache() error {
	err := e.downloadAgent()
	if err != nil {
		return err
	}

	log.Info("Loading Amazon Elastic Container Service Agent into Docker")
	return e.load(e.downloader.LoadCachedAgent())
}

func (e *Engine) downloadAgent() error {
	log.Info("Downloading Amazon Elastic Container Service Agent")
	err := e.downloader.DownloadAgent()
	if err != nil {
		return engineError("could not download Amazon Elastic Container Service Agent", err)
	}
	return nil
}

func (e *Engine) load(image io.ReadCloser, err error) error {
	if err != nil {
		return engineError("could not load Amazon Elastic Container Service Agent from cache", err)
	}
	defer image.Close()
	err = e.docker.LoadImage(image)
	if err != nil {
		return engineError("could not load Amazon Elastic Container Service Agent into Docker", err)
	}
	return e.downloader.RecordCachedAgent()
}

// StartSupervised starts the ECS Agent and ensures it stays running, except for terminal errors (indicated by an agent exit code of 5)
func (e *Engine) StartSupervised() error {
	agentExitCode := -1
	retryBackoff := backoff.NewBackoff(serviceStartMinRetryTime, serviceStartMaxRetryTime,
		serviceStartRetryJitter, serviceStartRetryMultiplier, serviceStartMaxRetries)
	for {
		err := e.docker.RemoveExistingAgentContainer()
		if err != nil {
			return engineError("could not remove existing Agent container", err)
		}

		log.Info("Starting Amazon Elastic Container Service Agent")
		agentExitCode, err = e.docker.StartAgent()
		if err != nil {
			return engineError("could not start Agent", err)
		}
		log.Infof("Agent exited with code %d", agentExitCode)

		switch agentExitCode {
		case upgradeAgentExitCode:
			err = e.upgradeAgent()
			if err != nil {
				log.Error("could not upgrade agent", err)
			} else {
				// continuing here because a successful upgrade doesn't need to backoff retries
				continue
			}
		case containerFailureAgentExitCode:
			// capture the tail of the failed agent container
			log.Infof("Captured the last %s lines of the agent container logs====>\n", failedContainerLogWindowSize)
			log.Info(e.docker.GetContainerLogTail(failedContainerLogWindowSize))
			log.Infof("<====end %s lines of the failed agent container logs\n", failedContainerLogWindowSize)
		case terminalFailureAgentExitCode:
			return errors.New("agent exited with terminal exit code")
		case terminalSuccessAgentExitCode:
			return nil
		}
		d := retryBackoff.Duration()
		log.Warnf("ECS Agent failed to start, retrying in %s", d)
		time.Sleep(d)
	}
}

func (e *Engine) upgradeAgent() error {
	log.Info("Loading new desired Amazon Elastic Container Service Agent into Docker")
	return e.load(e.downloader.LoadDesiredAgent())
}

// PreStop sends commands to Docker to stop the ECS Agent
func (e *Engine) PreStop() error {
	log.Info("Stopping Amazon Elastic Container Service Agent")
	err := e.docker.StopAgent()
	if err != nil {
		return engineError("could not stop Amazon Elastic Container Service Agent", err)
	}
	return nil
}

// PostStop cleans up the credentials endpoint setup by disabling loopback
// routing and removing the rerouting rule from the netfilter table
func (e *Engine) PostStop() error {
	log.Info("Cleaning up the credentials endpoint setup for Amazon Elastic Container Service Agent")
	err := e.loopbackRouting.RestoreDefault()

	// Ignore error from Remove() as the netfilter might never have been
	// addred in the first place
	e.credentialsProxyRoute.Remove()
	return err
}

type _engineError struct {
	err     error
	message string
}

func (e _engineError) Error() string {
	return fmt.Sprintf("%s: %s", e.message, e.err.Error())
}

func engineError(message string, err error) _engineError {
	return _engineError{
		message: message,
		err:     err,
	}
}
<commit_msg>Fix typo in comment (#357)<commit_after>// Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//     http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 engine

import (
	"errors"
	"fmt"
	"io"
	"math"
	"time"

	"github.com/aws/amazon-ecs-init/ecs-init/backoff"
	"github.com/aws/amazon-ecs-init/ecs-init/cache"
	"github.com/aws/amazon-ecs-init/ecs-init/config"
	"github.com/aws/amazon-ecs-init/ecs-init/docker"
	"github.com/aws/amazon-ecs-init/ecs-init/exec"
	"github.com/aws/amazon-ecs-init/ecs-init/exec/iptables"
	"github.com/aws/amazon-ecs-init/ecs-init/exec/sysctl"
	"github.com/aws/amazon-ecs-init/ecs-init/gpu"

	log "github.com/cihub/seelog"
)

const (
	terminalSuccessAgentExitCode  = 0
	containerFailureAgentExitCode = 2
	terminalFailureAgentExitCode  = 5
	upgradeAgentExitCode          = 42
	serviceStartMinRetryTime      = time.Millisecond * 500
	serviceStartMaxRetryTime      = time.Second * 15
	serviceStartRetryJitter       = 0.10
	serviceStartRetryMultiplier   = 2.0
	serviceStartMaxRetries        = math.MaxInt64 // essentially retry forever
	failedContainerLogWindowSize  = "200"         // as string for log config
)

// Engine contains methods invoked when ecs-init is run
type Engine struct {
	downloader               downloader
	docker                   dockerClient
	loopbackRouting          loopbackRouting
	credentialsProxyRoute    credentialsProxyRoute
	ipv6RouterAdvertisements ipv6RouterAdvertisements
	nvidiaGPUManager         gpu.GPUManager
}

// New creates an instance of Engine
func New() (*Engine, error) {
	downloader, err := cache.NewDownloader()
	if err != nil {
		return nil, err
	}
	docker, err := docker.NewClient()
	if err != nil {
		return nil, err
	}
	cmdExec := exec.NewExec()
	loopbackRouting, err := sysctl.NewIpv4RouteLocalNet(cmdExec)
	if err != nil {
		return nil, err
	}
	ipv6RouterAdvertisements, err := sysctl.NewIpv6RouterAdvertisements(cmdExec)
	if err != nil {
		return nil, err
	}
	credentialsProxyRoute, err := iptables.NewNetfilterRoute(cmdExec)
	if err != nil {
		return nil, err
	}
	return &Engine{
		downloader:               downloader,
		docker:                   docker,
		loopbackRouting:          loopbackRouting,
		credentialsProxyRoute:    credentialsProxyRoute,
		ipv6RouterAdvertisements: ipv6RouterAdvertisements,
		nvidiaGPUManager:         gpu.NewNvidiaGPUManager(),
	}, nil
}

// PreStart prepares the ECS Agent for starting. It also configures the instance
// to handle credentials requests from containers by rerouting these requests to
// to the ECS Agent's credentials endpoint
func (e *Engine) PreStart() error {
	// setup gpu if necessary
	err := e.PreStartGPU()
	if err != nil {
		return err
	}
	// Enable use of loopback addresses for local routing purposes
	err = e.loopbackRouting.Enable()
	if err != nil {
		return engineError("could not enable loopback routing", err)
	}
	// Disable ipv6 router advertisements
	err = e.ipv6RouterAdvertisements.Disable()
	if err != nil {
		return engineError("could not disable ipv6 router advertisements", err)
	}
	// Add the rerouting netfilter rule for credentials endpoint
	err = e.credentialsProxyRoute.Create()
	if err != nil {
		return engineError("could not create route to the credentials proxy", err)
	}

	imageLoaded, err := e.docker.IsAgentImageLoaded()
	if err != nil {
		return engineError("could not check Docker for Agent image presence", err)
	}

	switch e.downloader.AgentCacheStatus() {
	// Uncached, go get the Agent.
	case cache.StatusUncached:
		return e.downloadAndLoadCache()

	// The Agent is cached, and mandates a reload regardless of the
	// already loaded image.
	case cache.StatusReloadNeeded:
		return e.load(e.downloader.LoadCachedAgent())

	// Agent is cached, respect the already loaded Agent.
	case cache.StatusCached:
		if imageLoaded {
			return nil
		}
		return e.load(e.downloader.LoadCachedAgent())

	// There shouldn't be unhandled cache states.
	default:
		return errors.New("could not handle cache state")
	}
}

// PreStartGPU sets up the nvidia gpu manager if it's enabled.
func (e *Engine) PreStartGPU() error {
	envVariables := e.docker.LoadEnvVars()
	if val, ok := envVariables[config.GPUSupportEnvVar]; ok {
		if val == "true" {
			err := e.nvidiaGPUManager.Setup()
			if err != nil {
				log.Errorf("Nvidia GPU Manager: %v", err)
				return engineError("Nvidia GPU Manager", err)
			}
		}
	}
	return nil
}

// ReloadCache reloads the cached image of the ECS Agent into Docker
func (e *Engine) ReloadCache() error {
	cached := e.downloader.IsAgentCached()
	if !cached {
		return e.downloadAndLoadCache()
	}
	return e.load(e.downloader.LoadCachedAgent())
}

func (e *Engine) downloadAndLoadCache() error {
	err := e.downloadAgent()
	if err != nil {
		return err
	}

	log.Info("Loading Amazon Elastic Container Service Agent into Docker")
	return e.load(e.downloader.LoadCachedAgent())
}

func (e *Engine) downloadAgent() error {
	log.Info("Downloading Amazon Elastic Container Service Agent")
	err := e.downloader.DownloadAgent()
	if err != nil {
		return engineError("could not download Amazon Elastic Container Service Agent", err)
	}
	return nil
}

func (e *Engine) load(image io.ReadCloser, err error) error {
	if err != nil {
		return engineError("could not load Amazon Elastic Container Service Agent from cache", err)
	}
	defer image.Close()
	err = e.docker.LoadImage(image)
	if err != nil {
		return engineError("could not load Amazon Elastic Container Service Agent into Docker", err)
	}
	return e.downloader.RecordCachedAgent()
}

// StartSupervised starts the ECS Agent and ensures it stays running, except for terminal errors (indicated by an agent exit code of 5)
func (e *Engine) StartSupervised() error {
	agentExitCode := -1
	retryBackoff := backoff.NewBackoff(serviceStartMinRetryTime, serviceStartMaxRetryTime,
		serviceStartRetryJitter, serviceStartRetryMultiplier, serviceStartMaxRetries)
	for {
		err := e.docker.RemoveExistingAgentContainer()
		if err != nil {
			return engineError("could not remove existing Agent container", err)
		}

		log.Info("Starting Amazon Elastic Container Service Agent")
		agentExitCode, err = e.docker.StartAgent()
		if err != nil {
			return engineError("could not start Agent", err)
		}
		log.Infof("Agent exited with code %d", agentExitCode)

		switch agentExitCode {
		case upgradeAgentExitCode:
			err = e.upgradeAgent()
			if err != nil {
				log.Error("could not upgrade agent", err)
			} else {
				// continuing here because a successful upgrade doesn't need to backoff retries
				continue
			}
		case containerFailureAgentExitCode:
			// capture the tail of the failed agent container
			log.Infof("Captured the last %s lines of the agent container logs====>\n", failedContainerLogWindowSize)
			log.Info(e.docker.GetContainerLogTail(failedContainerLogWindowSize))
			log.Infof("<====end %s lines of the failed agent container logs\n", failedContainerLogWindowSize)
		case terminalFailureAgentExitCode:
			return errors.New("agent exited with terminal exit code")
		case terminalSuccessAgentExitCode:
			return nil
		}
		d := retryBackoff.Duration()
		log.Warnf("ECS Agent failed to start, retrying in %s", d)
		time.Sleep(d)
	}
}

func (e *Engine) upgradeAgent() error {
	log.Info("Loading new desired Amazon Elastic Container Service Agent into Docker")
	return e.load(e.downloader.LoadDesiredAgent())
}

// PreStop sends commands to Docker to stop the ECS Agent
func (e *Engine) PreStop() error {
	log.Info("Stopping Amazon Elastic Container Service Agent")
	err := e.docker.StopAgent()
	if err != nil {
		return engineError("could not stop Amazon Elastic Container Service Agent", err)
	}
	return nil
}

// PostStop cleans up the credentials endpoint setup by disabling loopback
// routing and removing the rerouting rule from the netfilter table
func (e *Engine) PostStop() error {
	log.Info("Cleaning up the credentials endpoint setup for Amazon Elastic Container Service Agent")
	err := e.loopbackRouting.RestoreDefault()

	// Ignore error from Remove() as the netfilter might never have been
	// added in the first place
	e.credentialsProxyRoute.Remove()
	return err
}

type _engineError struct {
	err     error
	message string
}

func (e _engineError) Error() string {
	return fmt.Sprintf("%s: %s", e.message, e.err.Error())
}

func engineError(message string, err error) _engineError {
	return _engineError{
		message: message,
		err:     err,
	}
}
<|endoftext|>


<commit_before>package core

import (
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/gobwas/glob"
	"github.com/mitchellh/go-homedir"
	ini "gopkg.in/ini.v1"
)

// Glob represents a glob pattern passed via `--glob`.
type Glob struct {
	Negated bool
	Pattern glob.Glob
}

// Match returns whether or not the Glob g matches the string query.
func (g Glob) Match(query string) bool {
	return g.Pattern.Match(query) != g.Negated
}

// NewGlob creates a Glob from the string pat.
func NewGlob(pat string) Glob {
	negate := false
	if strings.HasPrefix(pat, "!") {
		pat = strings.TrimLeft(pat, "!")
		negate = true
	}
	g, gerr := glob.Compile(pat)
	if !CheckError(gerr) {
		panic(gerr)
	}
	return Glob{Pattern: g, Negated: negate}
}

// AlertLevels holds the possible values for "level" in an external rule.
var AlertLevels = []string{"suggestion", "warning", "error"}

// LevelToInt allows us to easily compare levels in lint.go.
var LevelToInt = map[string]int{
	"suggestion": 0,
	"warning":    1,
	"error":      2,
}

// Config holds Vale's configuration, both from the CLI and its config file.
type Config struct {
	// General configuration
	Checks        []string                   // All checks to load
	GBaseStyles   []string                   // Global base style
	GChecks       map[string]bool            // Global checks
	IgnoredScopes []string                   // A list of HTML tags to ignore
	SkippedScopes []string                   // A list of HTML blocks to ignore
	BlockIgnores  map[string][]string        // A list of blocks to ignore
	TokenIgnores  map[string][]string        // A list of tokens to ignore
	MinAlertLevel int                        // Lowest alert level to display
	RuleToLevel   map[string]string          // Single-rule level changes
	SBaseStyles   map[string][]string        // Syntax-specific base styles
	SChecks       map[string]map[string]bool // Syntax-specific checks
	StylesPath    string                     // Directory with Rule.yml files
	WordTemplate  string                     // The template used in YAML -> regexp list conversions
	Parsers       map[string]string          // A map of syntax -> commands
	Formats       map[string]string          // A map of unknown -> known formats
	Path          string                     // The location of the config file

	SecToPat map[string]glob.Glob

	// Command-line configuration
	Output    string // (optional) output style ("line" or "CLI")
	Wrap      bool   // (optional) wrap output when CLI style
	NoExit    bool   // (optional) don't return a nonzero exit code on lint errors
	Sorted    bool   // (optional) sort files by their name for output
	Normalize bool   // (optional) replace each path separator with a slash ('/')
	Simple    bool   // (optional) lint all files line-by-line
	InExt     string // (optional) extension to associate with stdin
	Relative  bool   // (optional) return relative paths
}

// NewConfig initializes a Config.
func NewConfig() *Config {
	var cfg Config
	cfg.GChecks = make(map[string]bool)
	cfg.SBaseStyles = make(map[string][]string)
	cfg.SChecks = make(map[string]map[string]bool)
	cfg.MinAlertLevel = 1
	cfg.RuleToLevel = make(map[string]string)
	cfg.Parsers = make(map[string]string)
	cfg.Formats = make(map[string]string)
	cfg.BlockIgnores = make(map[string][]string)
	cfg.TokenIgnores = make(map[string][]string)
	cfg.SecToPat = make(map[string]glob.Glob)
	return &cfg
}

func validateLevel(key string, val string, cfg *Config) bool {
	options := []string{"YES", "suggestion", "warning", "error"}
	if val == "NO" || !StringInSlice(val, options) {
		return false
	} else if val != "YES" {
		cfg.RuleToLevel[key] = val
	}
	return true
}

// loadConfig loads the .vale file. It checks the current directory up to the
// user's home directory, stopping on the first occurrence of a .vale or _vale
// file.
func loadConfig(names, paths []string) (*ini.File, string, error) {
	var configPath, dir string
	var iniFile *ini.File
	var err error
	var recur bool

	for _, start := range paths {
		count := 0
		for configPath == "" && count < 6 {
			recur = start == "" && count == 0
			if recur {
				dir, _ = os.Getwd()
			} else if count == 0 {
				dir = start
				count = 6
			} else {
				dir = filepath.Dir(dir)
			}
			for _, name := range names {
				loc := path.Join(dir, name)
				if FileExists(loc) && !IsDir(loc) {
					configPath = loc
					if name == "" {
						dir = filepath.Dir(configPath)
					}
					break
				}
			}
			count++
		}
	}

	iniFile, err = ini.Load(configPath)
	return iniFile, dir, err
}

// LoadConfig reads the .vale/_vale file.
func LoadConfig(cfg *Config, upath string) (*Config, error) {
	names := []string{".vale", "_vale", "vale.ini", ".vale.ini", "_vale.ini", ""}
	home, _ := homedir.Dir()

	uCfg, path, err := loadConfig(names, []string{upath, "", home})
	if err != nil {
		return cfg, err
	}

	cfg.Path = path
	core := uCfg.Section("")
	global := uCfg.Section("*")
	formats := uCfg.Section("formats")

	// Default settings
	for _, k := range core.KeyStrings() {
		if k == "StylesPath" {
			cfg.StylesPath = DeterminePath(path, core.Key(k).MustString(""))
		} else if k == "MinAlertLevel" {
			level := core.Key(k).In("warning", AlertLevels)
			cfg.MinAlertLevel = LevelToInt[level]
		} else if k == "IgnoredScopes" {
			cfg.IgnoredScopes = core.Key(k).Strings(",")
		} else if k == "WordTemplate" {
			cfg.WordTemplate = core.Key(k).String()
		} else if k == "SkippedScopes" {
			cfg.SkippedScopes = core.Key(k).Strings(",")
		}
	}
	// Format mappings
	for _, k := range formats.KeyStrings() {
		cfg.Formats[k] = formats.Key(k).String()
	}

	// Global settings
	cfg.GBaseStyles = global.Key("BasedOnStyles").Strings(",")
	for _, k := range global.KeyStrings() {
		if k == "BasedOnStyles" {
			continue
		} else {
			cfg.GChecks[k] = validateLevel(k, global.Key(k).String(), cfg)
			cfg.Checks = append(cfg.Checks, k)
		}
	}

	// Syntax-specific settings
	for _, sec := range uCfg.SectionStrings() {
		if sec == "*" || sec == "DEFAULT" || sec == "formats" {
			continue
		}
		pat, err := glob.Compile(sec)
		if CheckError(err) {
			cfg.SecToPat[sec] = pat
		}
		syntaxOpts := make(map[string]bool)
		for _, k := range uCfg.Section(sec).KeyStrings() {
			if k == "BasedOnStyles" {
				pat, err := glob.Compile(sec)
				if _, found := cfg.SecToPat[sec]; !found && CheckError(err) {
					cfg.SecToPat[sec] = pat
				}
				cfg.SBaseStyles[sec] = uCfg.Section(sec).Key(k).Strings(",")
			} else if k == "IgnorePatterns" || k == "BlockIgnores" {
				cfg.BlockIgnores[sec] = uCfg.Section(sec).Key(k).Strings(",")
			} else if k == "TokenIgnores" {
				cfg.TokenIgnores[sec] = uCfg.Section(sec).Key(k).Strings(",")
			} else if k == "Parser" {
				cfg.Parsers[sec] = uCfg.Section(sec).Key(k).String()
			} else {
				syntaxOpts[k] = validateLevel(k, uCfg.Section(sec).Key(k).String(), cfg)
				cfg.Checks = append(cfg.Checks, k)
			}
		}
		cfg.SChecks[sec] = syntaxOpts
	}

	return cfg, err
}
<commit_msg>fix: ensure `DeterminePath` works with slashes<commit_after>package core

import (
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/gobwas/glob"
	"github.com/mitchellh/go-homedir"
	ini "gopkg.in/ini.v1"
)

// Glob represents a glob pattern passed via `--glob`.
type Glob struct {
	Negated bool
	Pattern glob.Glob
}

// Match returns whether or not the Glob g matches the string query.
func (g Glob) Match(query string) bool {
	return g.Pattern.Match(query) != g.Negated
}

// NewGlob creates a Glob from the string pat.
func NewGlob(pat string) Glob {
	negate := false
	if strings.HasPrefix(pat, "!") {
		pat = strings.TrimLeft(pat, "!")
		negate = true
	}
	g, gerr := glob.Compile(pat)
	if !CheckError(gerr) {
		panic(gerr)
	}
	return Glob{Pattern: g, Negated: negate}
}

// AlertLevels holds the possible values for "level" in an external rule.
var AlertLevels = []string{"suggestion", "warning", "error"}

// LevelToInt allows us to easily compare levels in lint.go.
var LevelToInt = map[string]int{
	"suggestion": 0,
	"warning":    1,
	"error":      2,
}

// Config holds Vale's configuration, both from the CLI and its config file.
type Config struct {
	// General configuration
	Checks        []string                   // All checks to load
	GBaseStyles   []string                   // Global base style
	GChecks       map[string]bool            // Global checks
	IgnoredScopes []string                   // A list of HTML tags to ignore
	SkippedScopes []string                   // A list of HTML blocks to ignore
	BlockIgnores  map[string][]string        // A list of blocks to ignore
	TokenIgnores  map[string][]string        // A list of tokens to ignore
	MinAlertLevel int                        // Lowest alert level to display
	RuleToLevel   map[string]string          // Single-rule level changes
	SBaseStyles   map[string][]string        // Syntax-specific base styles
	SChecks       map[string]map[string]bool // Syntax-specific checks
	StylesPath    string                     // Directory with Rule.yml files
	WordTemplate  string                     // The template used in YAML -> regexp list conversions
	Parsers       map[string]string          // A map of syntax -> commands
	Formats       map[string]string          // A map of unknown -> known formats
	Path          string                     // The location of the config file

	SecToPat map[string]glob.Glob

	// Command-line configuration
	Output    string // (optional) output style ("line" or "CLI")
	Wrap      bool   // (optional) wrap output when CLI style
	NoExit    bool   // (optional) don't return a nonzero exit code on lint errors
	Sorted    bool   // (optional) sort files by their name for output
	Normalize bool   // (optional) replace each path separator with a slash ('/')
	Simple    bool   // (optional) lint all files line-by-line
	InExt     string // (optional) extension to associate with stdin
	Relative  bool   // (optional) return relative paths
}

// NewConfig initializes a Config.
func NewConfig() *Config {
	var cfg Config
	cfg.GChecks = make(map[string]bool)
	cfg.SBaseStyles = make(map[string][]string)
	cfg.SChecks = make(map[string]map[string]bool)
	cfg.MinAlertLevel = 1
	cfg.RuleToLevel = make(map[string]string)
	cfg.Parsers = make(map[string]string)
	cfg.Formats = make(map[string]string)
	cfg.BlockIgnores = make(map[string][]string)
	cfg.TokenIgnores = make(map[string][]string)
	cfg.SecToPat = make(map[string]glob.Glob)
	return &cfg
}

func validateLevel(key string, val string, cfg *Config) bool {
	options := []string{"YES", "suggestion", "warning", "error"}
	if val == "NO" || !StringInSlice(val, options) {
		return false
	} else if val != "YES" {
		cfg.RuleToLevel[key] = val
	}
	return true
}

// loadConfig loads the .vale file. It checks the current directory up to the
// user's home directory, stopping on the first occurrence of a .vale or _vale
// file.
func loadConfig(names, paths []string) (*ini.File, string, error) {
	var configPath, dir string
	var iniFile *ini.File
	var err error
	var recur bool

	for _, start := range paths {
		count := 0
		for configPath == "" && count < 6 {
			recur = start == "" && count == 0
			if recur {
				dir, _ = os.Getwd()
			} else if count == 0 {
				dir = start
				count = 6
			} else {
				dir = filepath.Dir(dir)
			}
			for _, name := range names {
				loc := path.Join(dir, name)
				if FileExists(loc) && !IsDir(loc) {
					configPath = loc
					if name == "" {
						dir = filepath.Dir(configPath)
					}
					break
				}
			}
			count++
		}
	}

	iniFile, err = ini.Load(configPath)
	return iniFile, dir, err
}

// LoadConfig reads the .vale/_vale file.
func LoadConfig(cfg *Config, upath string) (*Config, error) {
	names := []string{".vale", "_vale", "vale.ini", ".vale.ini", "_vale.ini", ""}
	home, _ := homedir.Dir()

	uCfg, path, err := loadConfig(names, []string{upath, "", home})
	if err != nil {
		return cfg, err
	}

	cfg.Path = path
	core := uCfg.Section("")
	global := uCfg.Section("*")
	formats := uCfg.Section("formats")

	// Default settings
	for _, k := range core.KeyStrings() {
		if k == "StylesPath" {
			canidate := filepath.FromSlash(core.Key(k).MustString(""))
			cfg.StylesPath = DeterminePath(path, canidate)
		} else if k == "MinAlertLevel" {
			level := core.Key(k).In("warning", AlertLevels)
			cfg.MinAlertLevel = LevelToInt[level]
		} else if k == "IgnoredScopes" {
			cfg.IgnoredScopes = core.Key(k).Strings(",")
		} else if k == "WordTemplate" {
			cfg.WordTemplate = core.Key(k).String()
		} else if k == "SkippedScopes" {
			cfg.SkippedScopes = core.Key(k).Strings(",")
		}
	}
	// Format mappings
	for _, k := range formats.KeyStrings() {
		cfg.Formats[k] = formats.Key(k).String()
	}

	// Global settings
	cfg.GBaseStyles = global.Key("BasedOnStyles").Strings(",")
	for _, k := range global.KeyStrings() {
		if k == "BasedOnStyles" {
			continue
		} else {
			cfg.GChecks[k] = validateLevel(k, global.Key(k).String(), cfg)
			cfg.Checks = append(cfg.Checks, k)
		}
	}

	// Syntax-specific settings
	for _, sec := range uCfg.SectionStrings() {
		if sec == "*" || sec == "DEFAULT" || sec == "formats" {
			continue
		}
		pat, err := glob.Compile(sec)
		if CheckError(err) {
			cfg.SecToPat[sec] = pat
		}
		syntaxOpts := make(map[string]bool)
		for _, k := range uCfg.Section(sec).KeyStrings() {
			if k == "BasedOnStyles" {
				pat, err := glob.Compile(sec)
				if _, found := cfg.SecToPat[sec]; !found && CheckError(err) {
					cfg.SecToPat[sec] = pat
				}
				cfg.SBaseStyles[sec] = uCfg.Section(sec).Key(k).Strings(",")
			} else if k == "IgnorePatterns" || k == "BlockIgnores" {
				cfg.BlockIgnores[sec] = uCfg.Section(sec).Key(k).Strings(",")
			} else if k == "TokenIgnores" {
				cfg.TokenIgnores[sec] = uCfg.Section(sec).Key(k).Strings(",")
			} else if k == "Parser" {
				cfg.Parsers[sec] = uCfg.Section(sec).Key(k).String()
			} else {
				syntaxOpts[k] = validateLevel(k, uCfg.Section(sec).Key(k).String(), cfg)
				cfg.Checks = append(cfg.Checks, k)
			}
		}
		cfg.SChecks[sec] = syntaxOpts
	}

	return cfg, err
}
<|endoftext|>


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

package image

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"
	"time"

	"github.com/01org/ciao/service"
)

// TBD - can some of this stuff be pulled out into a common test area?
type test struct {
	method           string
	pattern          string
	handler          func(*Context, http.ResponseWriter, *http.Request) (APIResponse, error)
	request          string
	expectedStatus   int
	expectedResponse string
}

var tests = []test{
	{
		"GET",
		"/",
		listAPIVersions,
		"",
		http.StatusOK,
		`{"versions":[{"status":"CURRENT","id":"v2.3","links":[{"href":"` + fmt.Sprintf("https://%s:9292/v2/", myHostname()) + `","rel":"self"}]}]}`,
	},
	{
		"POST",
		"/v2/images",
		createImage,
		`{"container_format":"bare","disk_format":"raw","name":"Ubuntu","id":"b2173dd3-7ad6-4362-baa6-a68bce3565cb","visibility":"private"}`,
		http.StatusCreated,
		`{"status":"queued","container_format":"bare","min_ram":0,"updated_at":"2015-11-29T22:21:42Z","owner":"bab7d5c60cd041a0a36f7c4b6e1dd978","min_disk":0,"tags":[],"locations":[],"visibility":"private","id":"b2173dd3-7ad6-4362-baa6-a68bce3565cb","size":null,"virtual_size":null,"name":"Ubuntu","checksum":null,"created_at":"2015-11-29T22:21:42Z","disk_format":"raw","properties":null,"protected":false,"self":"/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb","file":"/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb/file","schema":"/v2/schemas/image"}`,
	},
	{
		"POST",
		"/v2/images",
		createImage,
		"",
		http.StatusInternalServerError,
		fmt.Sprintf("Internal Server Error\nnull"),
	},
	{
		"GET",
		"/v2/images",
		listImages,
		"",
		http.StatusOK,
		`{"images":[{"status":"queued","container_format":"bare","min_ram":0,"updated_at":"2015-11-29T22:21:42Z","owner":"bab7d5c60cd041a0a36f7c4b6e1dd978","min_disk":0,"tags":[],"locations":[],"visibility":"private","id":"b2173dd3-7ad6-4362-baa6-a68bce3565cb","size":null,"virtual_size":null,"name":"Ubuntu","checksum":null,"created_at":"2015-11-29T22:21:42Z","disk_format":"raw","properties":null,"protected":false,"self":"/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb","file":"/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb/file","schema":"/v2/schemas/image"}],"schema":"/v2/schemas/images","first":"/v2/images"}`,
	},
	{
		"GET",
		"/v2/images/1bea47ed-f6a9-463b-b423-14b9cca9ad27",
		getImage,
		"",
		http.StatusOK,
		`{"status":"active","container_format":"bare","min_ram":0,"updated_at":"2014-05-05T17:15:11Z","owner":"5ef70662f8b34079a6eddb8da9d75fe8","min_disk":0,"tags":[],"locations":[],"visibility":"public","id":"1bea47ed-f6a9-463b-b423-14b9cca9ad27","size":13167616,"virtual_size":null,"name":"cirros-0.3.2-x86_64-disk","checksum":"64d7c1cd2b6f60c92c14662941cb7913","created_at":"2014-05-05T17:15:10Z","disk_format":"qcow2","properties":null,"protected":false,"self":"/v2/images/1bea47ed-f6a9-463b-b423-14b9cca9ad27","file":"/v2/images/1bea47ed-f6a9-463b-b423-14b9cca9ad27/file","schema":"/v2/schemas/image"}`,
	},
	{
		"DELETE",
		"/v2/images/1bea47ed-f6a9-463b-b423-14b9cca9ad27",
		deleteImage,
		"",
		http.StatusNoContent,
		`null`,
	},
	{
		"PUT",
		"/v2/images/1bea47ed-f6a9-463b-b423-14b9cca9ad27",
		uploadImage,
		"",
		http.StatusNoContent,
		`null`,
	},
}

const testTenantID = "1bea47ed-f6a9-463b-b423-14b9cca9ad27"

func myHostname() string {
	host, _ := os.Hostname()
	return host
}

type testImageService struct{}

func (is testImageService) CreateImage(tenantID string, req CreateImageRequest) (DefaultResponse, error) {
	format := Bare
	name := "Ubuntu"
	createdAt, _ := time.Parse(time.RFC3339, "2015-11-29T22:21:42Z")
	updatedAt, _ := time.Parse(time.RFC3339, "2015-11-29T22:21:42Z")
	minDisk := 0
	minRAM := 0
	owner := "bab7d5c60cd041a0a36f7c4b6e1dd978"

	return DefaultResponse{
		Status:          Queued,
		ContainerFormat: &format,
		CreatedAt:       createdAt,
		Tags:            make([]string, 0),
		DiskFormat:      Raw,
		Visibility:      Private,
		UpdatedAt:       &updatedAt,
		Locations:       make([]string, 0),
		Self:            "/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb",
		MinDisk:         &minDisk,
		Protected:       false,
		ID:              "b2173dd3-7ad6-4362-baa6-a68bce3565cb",
		File:            "/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb/file",
		Owner:           &owner,
		MinRAM:          &minRAM,
		Schema:          "/v2/schemas/image",
		Name:            &name,
	}, nil
}

func (is testImageService) ListImages(tenantID string) ([]DefaultResponse, error) {
	format := Bare
	name := "Ubuntu"
	createdAt, _ := time.Parse(time.RFC3339, "2015-11-29T22:21:42Z")
	updatedAt, _ := time.Parse(time.RFC3339, "2015-11-29T22:21:42Z")
	minDisk := 0
	minRAM := 0
	owner := "bab7d5c60cd041a0a36f7c4b6e1dd978"

	image := DefaultResponse{
		Status:          Queued,
		ContainerFormat: &format,
		CreatedAt:       createdAt,
		Tags:            make([]string, 0),
		DiskFormat:      Raw,
		Visibility:      Private,
		UpdatedAt:       &updatedAt,
		Locations:       make([]string, 0),
		Self:            "/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb",
		MinDisk:         &minDisk,
		Protected:       false,
		ID:              "b2173dd3-7ad6-4362-baa6-a68bce3565cb",
		File:            "/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb/file",
		Owner:           &owner,
		MinRAM:          &minRAM,
		Schema:          "/v2/schemas/image",
		Name:            &name,
	}

	var images []DefaultResponse

	if tenantID == testTenantID {
		images = append(images, image)
	}

	return images, nil
}

func (is testImageService) GetImage(tenantID, ID string) (DefaultResponse, error) {
	imageID := "1bea47ed-f6a9-463b-b423-14b9cca9ad27"
	format := Bare
	name := "cirros-0.3.2-x86_64-disk"
	createdAt, _ := time.Parse(time.RFC3339, "2014-05-05T17:15:10Z")
	updatedAt, _ := time.Parse(time.RFC3339, "2014-05-05T17:15:11Z")
	minDisk := 0
	minRAM := 0
	owner := "5ef70662f8b34079a6eddb8da9d75fe8"
	checksum := "64d7c1cd2b6f60c92c14662941cb7913"
	size := 13167616

	return DefaultResponse{
		Status:          Active,
		ContainerFormat: &format,
		CreatedAt:       createdAt,
		Tags:            make([]string, 0),
		DiskFormat:      QCow,
		Visibility:      Public,
		UpdatedAt:       &updatedAt,
		Locations:       make([]string, 0),
		Self:            fmt.Sprintf("/v2/images/%s", imageID),
		MinDisk:         &minDisk,
		Protected:       false,
		CheckSum:        &checksum,
		ID:              imageID,

		File:   fmt.Sprintf("/v2/images/%s/file", imageID),
		Owner:  &owner,
		MinRAM: &minRAM,
		Schema: "/v2/schemas/image",
		Name:   &name,
		Size:   &size,
	}, nil
}

func (is testImageService) UploadImage(string, string, io.Reader) (NoContentImageResponse, error) {
	return NoContentImageResponse{}, nil
}

func (is testImageService) DeleteImage(string, string) (NoContentImageResponse, error) {
	return NoContentImageResponse{}, nil
}

func TestRoutes(t *testing.T) {
	var is testImageService
	config := APIConfig{9292, is}

	r := Routes(config, nil)
	if r == nil {
		t.Fatalf("No routes returned")
	}
}

func TestAPIResponse(t *testing.T) {
	var is testImageService

	// TBD: add context to test definition so it can be created per
	// endpoint with either a pass testVolumeService or a failure
	// one.
	context := &Context{9292, is, nil}

	for _, tt := range tests {
		req, err := http.NewRequest(tt.method, tt.pattern, bytes.NewBuffer([]byte(tt.request)))
		if err != nil {
			t.Fatal(err)
		}
		rr := httptest.NewRecorder()
		handler := APIHandler{context, tt.handler}

		ctx := service.SetPrivilege(req.Context(), true)
		ctx = service.SetTenantID(ctx, testTenantID)
		if err != nil {
			t.Fatalf("Error on setting tenant [%v]", testTenantID)
		}

		handler.ServeHTTP(rr, req.WithContext(ctx))

		status := rr.Code
		if status != tt.expectedStatus {
			t.Errorf("got %v, expected %v", status, tt.expectedStatus)
		}

		if rr.Body.String() != tt.expectedResponse {
			t.Errorf("%s: failed\ngot: %v\nexp: %v", tt.pattern, rr.Body.String(), tt.expectedResponse)
		}
	}
}
<commit_msg>openstack/image: Update unit test to reflect direct error returning<commit_after>// Copyright (c) 2016 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package image

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"
	"time"

	"github.com/01org/ciao/service"
)

// TBD - can some of this stuff be pulled out into a common test area?
type test struct {
	method           string
	pattern          string
	handler          func(*Context, http.ResponseWriter, *http.Request) (APIResponse, error)
	request          string
	expectedStatus   int
	expectedResponse string
}

var tests = []test{
	{
		"GET",
		"/",
		listAPIVersions,
		"",
		http.StatusOK,
		`{"versions":[{"status":"CURRENT","id":"v2.3","links":[{"href":"` + fmt.Sprintf("https://%s:9292/v2/", myHostname()) + `","rel":"self"}]}]}`,
	},
	{
		"POST",
		"/v2/images",
		createImage,
		`{"container_format":"bare","disk_format":"raw","name":"Ubuntu","id":"b2173dd3-7ad6-4362-baa6-a68bce3565cb","visibility":"private"}`,
		http.StatusCreated,
		`{"status":"queued","container_format":"bare","min_ram":0,"updated_at":"2015-11-29T22:21:42Z","owner":"bab7d5c60cd041a0a36f7c4b6e1dd978","min_disk":0,"tags":[],"locations":[],"visibility":"private","id":"b2173dd3-7ad6-4362-baa6-a68bce3565cb","size":null,"virtual_size":null,"name":"Ubuntu","checksum":null,"created_at":"2015-11-29T22:21:42Z","disk_format":"raw","properties":null,"protected":false,"self":"/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb","file":"/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb/file","schema":"/v2/schemas/image"}`,
	},
	{
		"POST",
		"/v2/images",
		createImage,
		"",
		http.StatusInternalServerError,
		fmt.Sprintf("unexpected end of JSON input\nnull"),
	},
	{
		"GET",
		"/v2/images",
		listImages,
		"",
		http.StatusOK,
		`{"images":[{"status":"queued","container_format":"bare","min_ram":0,"updated_at":"2015-11-29T22:21:42Z","owner":"bab7d5c60cd041a0a36f7c4b6e1dd978","min_disk":0,"tags":[],"locations":[],"visibility":"private","id":"b2173dd3-7ad6-4362-baa6-a68bce3565cb","size":null,"virtual_size":null,"name":"Ubuntu","checksum":null,"created_at":"2015-11-29T22:21:42Z","disk_format":"raw","properties":null,"protected":false,"self":"/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb","file":"/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb/file","schema":"/v2/schemas/image"}],"schema":"/v2/schemas/images","first":"/v2/images"}`,
	},
	{
		"GET",
		"/v2/images/1bea47ed-f6a9-463b-b423-14b9cca9ad27",
		getImage,
		"",
		http.StatusOK,
		`{"status":"active","container_format":"bare","min_ram":0,"updated_at":"2014-05-05T17:15:11Z","owner":"5ef70662f8b34079a6eddb8da9d75fe8","min_disk":0,"tags":[],"locations":[],"visibility":"public","id":"1bea47ed-f6a9-463b-b423-14b9cca9ad27","size":13167616,"virtual_size":null,"name":"cirros-0.3.2-x86_64-disk","checksum":"64d7c1cd2b6f60c92c14662941cb7913","created_at":"2014-05-05T17:15:10Z","disk_format":"qcow2","properties":null,"protected":false,"self":"/v2/images/1bea47ed-f6a9-463b-b423-14b9cca9ad27","file":"/v2/images/1bea47ed-f6a9-463b-b423-14b9cca9ad27/file","schema":"/v2/schemas/image"}`,
	},
	{
		"DELETE",
		"/v2/images/1bea47ed-f6a9-463b-b423-14b9cca9ad27",
		deleteImage,
		"",
		http.StatusNoContent,
		`null`,
	},
	{
		"PUT",
		"/v2/images/1bea47ed-f6a9-463b-b423-14b9cca9ad27",
		uploadImage,
		"",
		http.StatusNoContent,
		`null`,
	},
}

const testTenantID = "1bea47ed-f6a9-463b-b423-14b9cca9ad27"

func myHostname() string {
	host, _ := os.Hostname()
	return host
}

type testImageService struct{}

func (is testImageService) CreateImage(tenantID string, req CreateImageRequest) (DefaultResponse, error) {
	format := Bare
	name := "Ubuntu"
	createdAt, _ := time.Parse(time.RFC3339, "2015-11-29T22:21:42Z")
	updatedAt, _ := time.Parse(time.RFC3339, "2015-11-29T22:21:42Z")
	minDisk := 0
	minRAM := 0
	owner := "bab7d5c60cd041a0a36f7c4b6e1dd978"

	return DefaultResponse{
		Status:          Queued,
		ContainerFormat: &format,
		CreatedAt:       createdAt,
		Tags:            make([]string, 0),
		DiskFormat:      Raw,
		Visibility:      Private,
		UpdatedAt:       &updatedAt,
		Locations:       make([]string, 0),
		Self:            "/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb",
		MinDisk:         &minDisk,
		Protected:       false,
		ID:              "b2173dd3-7ad6-4362-baa6-a68bce3565cb",
		File:            "/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb/file",
		Owner:           &owner,
		MinRAM:          &minRAM,
		Schema:          "/v2/schemas/image",
		Name:            &name,
	}, nil
}

func (is testImageService) ListImages(tenantID string) ([]DefaultResponse, error) {
	format := Bare
	name := "Ubuntu"
	createdAt, _ := time.Parse(time.RFC3339, "2015-11-29T22:21:42Z")
	updatedAt, _ := time.Parse(time.RFC3339, "2015-11-29T22:21:42Z")
	minDisk := 0
	minRAM := 0
	owner := "bab7d5c60cd041a0a36f7c4b6e1dd978"

	image := DefaultResponse{
		Status:          Queued,
		ContainerFormat: &format,
		CreatedAt:       createdAt,
		Tags:            make([]string, 0),
		DiskFormat:      Raw,
		Visibility:      Private,
		UpdatedAt:       &updatedAt,
		Locations:       make([]string, 0),
		Self:            "/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb",
		MinDisk:         &minDisk,
		Protected:       false,
		ID:              "b2173dd3-7ad6-4362-baa6-a68bce3565cb",
		File:            "/v2/images/b2173dd3-7ad6-4362-baa6-a68bce3565cb/file",
		Owner:           &owner,
		MinRAM:          &minRAM,
		Schema:          "/v2/schemas/image",
		Name:            &name,
	}

	var images []DefaultResponse

	if tenantID == testTenantID {
		images = append(images, image)
	}

	return images, nil
}

func (is testImageService) GetImage(tenantID, ID string) (DefaultResponse, error) {
	imageID := "1bea47ed-f6a9-463b-b423-14b9cca9ad27"
	format := Bare
	name := "cirros-0.3.2-x86_64-disk"
	createdAt, _ := time.Parse(time.RFC3339, "2014-05-05T17:15:10Z")
	updatedAt, _ := time.Parse(time.RFC3339, "2014-05-05T17:15:11Z")
	minDisk := 0
	minRAM := 0
	owner := "5ef70662f8b34079a6eddb8da9d75fe8"
	checksum := "64d7c1cd2b6f60c92c14662941cb7913"
	size := 13167616

	return DefaultResponse{
		Status:          Active,
		ContainerFormat: &format,
		CreatedAt:       createdAt,
		Tags:            make([]string, 0),
		DiskFormat:      QCow,
		Visibility:      Public,
		UpdatedAt:       &updatedAt,
		Locations:       make([]string, 0),
		Self:            fmt.Sprintf("/v2/images/%s", imageID),
		MinDisk:         &minDisk,
		Protected:       false,
		CheckSum:        &checksum,
		ID:              imageID,

		File:   fmt.Sprintf("/v2/images/%s/file", imageID),
		Owner:  &owner,
		MinRAM: &minRAM,
		Schema: "/v2/schemas/image",
		Name:   &name,
		Size:   &size,
	}, nil
}

func (is testImageService) UploadImage(string, string, io.Reader) (NoContentImageResponse, error) {
	return NoContentImageResponse{}, nil
}

func (is testImageService) DeleteImage(string, string) (NoContentImageResponse, error) {
	return NoContentImageResponse{}, nil
}

func TestRoutes(t *testing.T) {
	var is testImageService
	config := APIConfig{9292, is}

	r := Routes(config, nil)
	if r == nil {
		t.Fatalf("No routes returned")
	}
}

func TestAPIResponse(t *testing.T) {
	var is testImageService

	// TBD: add context to test definition so it can be created per
	// endpoint with either a pass testVolumeService or a failure
	// one.
	context := &Context{9292, is, nil}

	for _, tt := range tests {
		req, err := http.NewRequest(tt.method, tt.pattern, bytes.NewBuffer([]byte(tt.request)))
		if err != nil {
			t.Fatal(err)
		}
		rr := httptest.NewRecorder()
		handler := APIHandler{context, tt.handler}

		ctx := service.SetPrivilege(req.Context(), true)
		ctx = service.SetTenantID(ctx, testTenantID)
		if err != nil {
			t.Fatalf("Error on setting tenant [%v]", testTenantID)
		}

		handler.ServeHTTP(rr, req.WithContext(ctx))

		status := rr.Code
		if status != tt.expectedStatus {
			t.Errorf("got %v, expected %v", status, tt.expectedStatus)
		}

		if rr.Body.String() != tt.expectedResponse {
			t.Errorf("%s: failed\ngot: %v\nexp: %v", tt.pattern, rr.Body.String(), tt.expectedResponse)
		}
	}
}
<|endoftext|>


<commit_before>package css

import (
	"fmt"

	"github.com/sparkymat/webdsl/css/display"
	"github.com/sparkymat/webdsl/css/flex"
)

func Display(value display.Type) Property {
	property := Property{propertyType: "display"}
	property.values = append(property.values, string(value))

	return property
}

func FlexDirection(value flex.Direction) Property {
	property := Property{propertyType: "flex-direction"}
	property.values = append(property.values, string(value))

	return property
}

func FlexWrap(value flex.WrapType) Property {
	property := Property{propertyType: "flex-wrap"}
	property.values = append(property.values, string(value))

	return property
}

func FlexGrow(value int) Property {
	property := Property{propertyType: "flex-grow"}
	property.values = append(property.values, fmt.Sprintf("%v", value))

	return property
}

//TODO this is used for flex box only. move this somewhere
type itemAlign string

const Center itemAlign = "center"
const Stretch itemAlign = "stretch"

func AlignItems(value itemAlign) Property {
	property := Property{propertyType: "align-items"}
	property.values = append(property.values, string(value))

	return property
}

type justifyContent string

const FlexEnd justifyContent = "flex-end"

func JustifyContent(value justifyContent) Property {
	property := Property{propertyType: "justify-content"}
	property.values = append(property.values, string(value))

	return property
}
<commit_msg>Added FlexShrink<commit_after>package css

import (
	"fmt"

	"github.com/sparkymat/webdsl/css/display"
	"github.com/sparkymat/webdsl/css/flex"
)

func Display(value display.Type) Property {
	property := Property{propertyType: "display"}
	property.values = append(property.values, string(value))

	return property
}

func FlexDirection(value flex.Direction) Property {
	property := Property{propertyType: "flex-direction"}
	property.values = append(property.values, string(value))

	return property
}

func FlexWrap(value flex.WrapType) Property {
	property := Property{propertyType: "flex-wrap"}
	property.values = append(property.values, string(value))

	return property
}

func FlexGrow(value int) Property {
	property := Property{propertyType: "flex-grow"}
	property.values = append(property.values, fmt.Sprintf("%v", value))

	return property
}

func FlexShrink(value int) Property {
	property := Property{propertyType: "flex-shrink"}
	property.values = append(property.values, fmt.Sprintf("%v", value))

	return property
}

//TODO this is used for flex box only. move this somewhere
type itemAlign string

const Center itemAlign = "center"
const Stretch itemAlign = "stretch"

func AlignItems(value itemAlign) Property {
	property := Property{propertyType: "align-items"}
	property.values = append(property.values, string(value))

	return property
}

type justifyContent string

const FlexEnd justifyContent = "flex-end"

func JustifyContent(value justifyContent) Property {
	property := Property{propertyType: "justify-content"}
	property.values = append(property.values, string(value))

	return property
}
<|endoftext|>


<commit_before>/*
	Utility functions used by all of ctfe.
*/

package util

import (
	"fmt"
	"net/http"
	"strings"
	"text/template"

	"go.skia.org/infra/go/httputils"
	"go.skia.org/infra/go/login"
)

// URIs for frontend handlers.
const (
	CHROMIUM_PERF_URI                       = "chromium_perf/"
	CHROMIUM_PERF_RUNS_URI                  = "chromium_perf_runs/"
	GET_CHROMIUM_PERF_RUN_STATUS_URI        = "get_chromium_perf_run_status"
	CHROMIUM_PERF_PARAMETERS_POST_URI       = "_/chromium_perf/"
	ADD_CHROMIUM_PERF_TASK_POST_URI         = "_/add_chromium_perf_task"
	GET_CHROMIUM_PERF_TASKS_POST_URI        = "_/get_chromium_perf_tasks"
	UPDATE_CHROMIUM_PERF_TASK_POST_URI      = "_/update_chromium_perf_task"
	WEBHOOK_ADD_CHROMIUM_PERF_TASK_POST_URI = "_/webhook_add_chromium_perf_task"
	DELETE_CHROMIUM_PERF_TASK_POST_URI      = "_/delete_chromium_perf_task"
	REDO_CHROMIUM_PERF_TASK_POST_URI        = "_/redo_chromium_perf_task"

	CHROMIUM_ANALYSIS_URI                  = "chromium_analysis/"
	CHROMIUM_ANALYSIS_RUNS_URI             = "chromium_analysis_runs/"
	ADD_CHROMIUM_ANALYSIS_TASK_POST_URI    = "_/add_chromium_analysis_task"
	GET_CHROMIUM_ANALYSIS_TASKS_POST_URI   = "_/get_chromium_analysis_tasks"
	UPDATE_CHROMIUM_ANALYSIS_TASK_POST_URI = "_/update_chromium_analysis_task"
	DELETE_CHROMIUM_ANALYSIS_TASK_POST_URI = "_/delete_chromium_analysis_task"
	REDO_CHROMIUM_ANALYSIS_TASK_POST_URI   = "_/redo_chromium_analysis_task"

	CAPTURE_SKPS_URI                  = "capture_skps/"
	CAPTURE_SKPS_RUNS_URI             = "capture_skp_runs/"
	ADD_CAPTURE_SKPS_TASK_POST_URI    = "_/add_capture_skps_task"
	GET_CAPTURE_SKPS_TASKS_POST_URI   = "_/get_capture_skp_tasks"
	UPDATE_CAPTURE_SKPS_TASK_POST_URI = "_/update_capture_skps_task"
	DELETE_CAPTURE_SKPS_TASK_POST_URI = "_/delete_capture_skps_task"
	REDO_CAPTURE_SKPS_TASK_POST_URI   = "_/redo_capture_skps_task"

	LUA_SCRIPT_URI                  = "lua_script/"
	LUA_SCRIPT_RUNS_URI             = "lua_script_runs/"
	ADD_LUA_SCRIPT_TASK_POST_URI    = "_/add_lua_script_task"
	GET_LUA_SCRIPT_TASKS_POST_URI   = "_/get_lua_script_tasks"
	UPDATE_LUA_SCRIPT_TASK_POST_URI = "_/update_lua_script_task"
	DELETE_LUA_SCRIPT_TASK_POST_URI = "_/delete_lua_script_task"
	REDO_LUA_SCRIPT_TASK_POST_URI   = "_/redo_lua_script_task"

	CHROMIUM_BUILD_URI                  = "chromium_builds/"
	CHROMIUM_BUILD_RUNS_URI             = "chromium_builds_runs/"
	CHROMIUM_REV_DATA_POST_URI          = "_/chromium_rev_data"
	SKIA_REV_DATA_POST_URI              = "_/skia_rev_data"
	ADD_CHROMIUM_BUILD_TASK_POST_URI    = "_/add_chromium_build_task"
	GET_CHROMIUM_BUILD_TASKS_POST_URI   = "_/get_chromium_build_tasks"
	UPDATE_CHROMIUM_BUILD_TASK_POST_URI = "_/update_chromium_build_task"
	DELETE_CHROMIUM_BUILD_TASK_POST_URI = "_/delete_chromium_build_task"
	REDO_CHROMIUM_BUILD_TASK_POST_URI   = "_/redo_chromium_build_task"

	ADMIN_TASK_URI = "admin_tasks/"

	RECREATE_PAGE_SETS_RUNS_URI             = "recreate_page_sets_runs/"
	ADD_RECREATE_PAGE_SETS_TASK_POST_URI    = "_/add_recreate_page_sets_task"
	GET_RECREATE_PAGE_SETS_TASKS_POST_URI   = "_/get_recreate_page_sets_tasks"
	UPDATE_RECREATE_PAGE_SETS_TASK_POST_URI = "_/update_recreate_page_sets_task"
	DELETE_RECREATE_PAGE_SETS_TASK_POST_URI = "_/delete_recreate_page_sets_task"
	REDO_RECREATE_PAGE_SETS_TASK_POST_URI   = "_/redo_recreate_page_sets_task"

	RECREATE_WEBPAGE_ARCHIVES_RUNS_URI             = "recreate_webpage_archives_runs/"
	ADD_RECREATE_WEBPAGE_ARCHIVES_TASK_POST_URI    = "_/add_recreate_webpage_archives_task"
	GET_RECREATE_WEBPAGE_ARCHIVES_TASKS_POST_URI   = "_/get_recreate_webpage_archives_tasks"
	UPDATE_RECREATE_WEBPAGE_ARCHIVES_TASK_POST_URI = "_/update_recreate_webpage_archives_task"
	DELETE_RECREATE_WEBPAGE_ARCHIVES_TASK_POST_URI = "_/delete_recreate_webpage_archives_task"
	REDO_RECREATE_WEBPAGE_ARCHIVES_TASK_POST_URI   = "_/redo_recreate_webpage_archives_task"

	RUNS_HISTORY_URI = "history/"

	PENDING_TASKS_URI           = "queue/"
	GET_OLDEST_PENDING_TASK_URI = "_/get_oldest_pending_task"

	PAGE_SETS_PARAMETERS_POST_URI = "_/page_sets/"
	CL_DATA_POST_URI              = "_/cl_data"
)

// Function to run before executing a template.
var PreExecuteTemplateHook = func() {}

func UserHasEditRights(r *http.Request) bool {
	return strings.HasSuffix(login.LoggedInAs(r), "@google.com") || strings.HasSuffix(login.LoggedInAs(r), "@chromium.org")
}

func UserHasAdminRights(r *http.Request) bool {
	// TODO(benjaminwagner): Add this list to GCE project level metadata and retrieve from there.
	admins := map[string]bool{
		"benjaminwagner@google.com": true,
		"borenet@google.com":        true,
		"jcgregorio@google.com":     true,
		"rmistry@google.com":        true,
		"stephana@google.com":       true,
	}
	return UserHasEditRights(r) && admins[login.LoggedInAs(r)]
}

func ExecuteSimpleTemplate(template *template.Template, w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	PreExecuteTemplateHook()
	if err := template.Execute(w, struct{}{}); err != nil {
		httputils.ReportError(w, r, err, fmt.Sprintf("Failed to expand template: %v", err))
		return
	}
}

type LengthCheck struct {
	Name  string
	Value string
	Limit int64
}

func CheckLengths(checks []LengthCheck) error {
	for _, check := range checks {
		if int64(len(check.Value)) > check.Limit {
			return fmt.Errorf("Value of %s is too long; limit %d bytes", check.Name, check.Limit)
		}
	}
	return nil
}
<commit_msg>Use login.IsAdmin() in CTFE.<commit_after>/*
	Utility functions used by all of ctfe.
*/

package util

import (
	"fmt"
	"net/http"
	"strings"
	"text/template"

	"go.skia.org/infra/go/httputils"
	"go.skia.org/infra/go/login"
)

// URIs for frontend handlers.
const (
	CHROMIUM_PERF_URI                       = "chromium_perf/"
	CHROMIUM_PERF_RUNS_URI                  = "chromium_perf_runs/"
	GET_CHROMIUM_PERF_RUN_STATUS_URI        = "get_chromium_perf_run_status"
	CHROMIUM_PERF_PARAMETERS_POST_URI       = "_/chromium_perf/"
	ADD_CHROMIUM_PERF_TASK_POST_URI         = "_/add_chromium_perf_task"
	GET_CHROMIUM_PERF_TASKS_POST_URI        = "_/get_chromium_perf_tasks"
	UPDATE_CHROMIUM_PERF_TASK_POST_URI      = "_/update_chromium_perf_task"
	WEBHOOK_ADD_CHROMIUM_PERF_TASK_POST_URI = "_/webhook_add_chromium_perf_task"
	DELETE_CHROMIUM_PERF_TASK_POST_URI      = "_/delete_chromium_perf_task"
	REDO_CHROMIUM_PERF_TASK_POST_URI        = "_/redo_chromium_perf_task"

	CHROMIUM_ANALYSIS_URI                  = "chromium_analysis/"
	CHROMIUM_ANALYSIS_RUNS_URI             = "chromium_analysis_runs/"
	ADD_CHROMIUM_ANALYSIS_TASK_POST_URI    = "_/add_chromium_analysis_task"
	GET_CHROMIUM_ANALYSIS_TASKS_POST_URI   = "_/get_chromium_analysis_tasks"
	UPDATE_CHROMIUM_ANALYSIS_TASK_POST_URI = "_/update_chromium_analysis_task"
	DELETE_CHROMIUM_ANALYSIS_TASK_POST_URI = "_/delete_chromium_analysis_task"
	REDO_CHROMIUM_ANALYSIS_TASK_POST_URI   = "_/redo_chromium_analysis_task"

	CAPTURE_SKPS_URI                  = "capture_skps/"
	CAPTURE_SKPS_RUNS_URI             = "capture_skp_runs/"
	ADD_CAPTURE_SKPS_TASK_POST_URI    = "_/add_capture_skps_task"
	GET_CAPTURE_SKPS_TASKS_POST_URI   = "_/get_capture_skp_tasks"
	UPDATE_CAPTURE_SKPS_TASK_POST_URI = "_/update_capture_skps_task"
	DELETE_CAPTURE_SKPS_TASK_POST_URI = "_/delete_capture_skps_task"
	REDO_CAPTURE_SKPS_TASK_POST_URI   = "_/redo_capture_skps_task"

	LUA_SCRIPT_URI                  = "lua_script/"
	LUA_SCRIPT_RUNS_URI             = "lua_script_runs/"
	ADD_LUA_SCRIPT_TASK_POST_URI    = "_/add_lua_script_task"
	GET_LUA_SCRIPT_TASKS_POST_URI   = "_/get_lua_script_tasks"
	UPDATE_LUA_SCRIPT_TASK_POST_URI = "_/update_lua_script_task"
	DELETE_LUA_SCRIPT_TASK_POST_URI = "_/delete_lua_script_task"
	REDO_LUA_SCRIPT_TASK_POST_URI   = "_/redo_lua_script_task"

	CHROMIUM_BUILD_URI                  = "chromium_builds/"
	CHROMIUM_BUILD_RUNS_URI             = "chromium_builds_runs/"
	CHROMIUM_REV_DATA_POST_URI          = "_/chromium_rev_data"
	SKIA_REV_DATA_POST_URI              = "_/skia_rev_data"
	ADD_CHROMIUM_BUILD_TASK_POST_URI    = "_/add_chromium_build_task"
	GET_CHROMIUM_BUILD_TASKS_POST_URI   = "_/get_chromium_build_tasks"
	UPDATE_CHROMIUM_BUILD_TASK_POST_URI = "_/update_chromium_build_task"
	DELETE_CHROMIUM_BUILD_TASK_POST_URI = "_/delete_chromium_build_task"
	REDO_CHROMIUM_BUILD_TASK_POST_URI   = "_/redo_chromium_build_task"

	ADMIN_TASK_URI = "admin_tasks/"

	RECREATE_PAGE_SETS_RUNS_URI             = "recreate_page_sets_runs/"
	ADD_RECREATE_PAGE_SETS_TASK_POST_URI    = "_/add_recreate_page_sets_task"
	GET_RECREATE_PAGE_SETS_TASKS_POST_URI   = "_/get_recreate_page_sets_tasks"
	UPDATE_RECREATE_PAGE_SETS_TASK_POST_URI = "_/update_recreate_page_sets_task"
	DELETE_RECREATE_PAGE_SETS_TASK_POST_URI = "_/delete_recreate_page_sets_task"
	REDO_RECREATE_PAGE_SETS_TASK_POST_URI   = "_/redo_recreate_page_sets_task"

	RECREATE_WEBPAGE_ARCHIVES_RUNS_URI             = "recreate_webpage_archives_runs/"
	ADD_RECREATE_WEBPAGE_ARCHIVES_TASK_POST_URI    = "_/add_recreate_webpage_archives_task"
	GET_RECREATE_WEBPAGE_ARCHIVES_TASKS_POST_URI   = "_/get_recreate_webpage_archives_tasks"
	UPDATE_RECREATE_WEBPAGE_ARCHIVES_TASK_POST_URI = "_/update_recreate_webpage_archives_task"
	DELETE_RECREATE_WEBPAGE_ARCHIVES_TASK_POST_URI = "_/delete_recreate_webpage_archives_task"
	REDO_RECREATE_WEBPAGE_ARCHIVES_TASK_POST_URI   = "_/redo_recreate_webpage_archives_task"

	RUNS_HISTORY_URI = "history/"

	PENDING_TASKS_URI           = "queue/"
	GET_OLDEST_PENDING_TASK_URI = "_/get_oldest_pending_task"

	PAGE_SETS_PARAMETERS_POST_URI = "_/page_sets/"
	CL_DATA_POST_URI              = "_/cl_data"
)

// Function to run before executing a template.
var PreExecuteTemplateHook = func() {}

func UserHasEditRights(r *http.Request) bool {
	return strings.HasSuffix(login.LoggedInAs(r), "@google.com") || strings.HasSuffix(login.LoggedInAs(r), "@chromium.org")
}

func UserHasAdminRights(r *http.Request) bool {
	return UserHasEditRights(r) && login.IsAdmin(r)
}

func ExecuteSimpleTemplate(template *template.Template, w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	PreExecuteTemplateHook()
	if err := template.Execute(w, struct{}{}); err != nil {
		httputils.ReportError(w, r, err, fmt.Sprintf("Failed to expand template: %v", err))
		return
	}
}

type LengthCheck struct {
	Name  string
	Value string
	Limit int64
}

func CheckLengths(checks []LengthCheck) error {
	for _, check := range checks {
		if int64(len(check.Value)) > check.Limit {
			return fmt.Errorf("Value of %s is too long; limit %d bytes", check.Name, check.Limit)
		}
	}
	return nil
}
<|endoftext|>