<commit_before>package websocket

import (
	"github.com/smancke/guble/protocol"
	"github.com/smancke/guble/server/auth"
	"github.com/smancke/guble/server/router"

	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/websocket"
	"github.com/rs/xid"

	"fmt"
	"net/http"
	"strings"
	"time"
)

var webSocketUpgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true },
}

// WSHandler is a struct used for handling websocket connections on a certain prefix.
type WSHandler struct {
	router        router.Router
	prefix        string
	accessManager auth.AccessManager
}

// NewWSHandler returns a new WSHandler.
func NewWSHandler(router router.Router, prefix string) (*WSHandler, error) {
	accessManager, err := router.AccessManager()
	if err != nil {
		return nil, err
	}
	return &WSHandler{
		router:        router,
		prefix:        prefix,
		accessManager: accessManager,
	}, nil
}

// GetPrefix returns the prefix.
// It is a part of the service.endpoint implementation.
func (handler *WSHandler) GetPrefix() string {
	return handler.prefix
}

// ServeHTTP is an http.Handler.
// It is a part of the service.endpoint implementation.
func (handler *WSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c, err := webSocketUpgrader.Upgrade(w, r, nil)
	if err != nil {
		logger.WithError(err).Error("Error on upgrading to websocket")
		return
	}
	defer c.Close()

	NewWebSocket(handler, &wsconn{c}, extractUserID(r.RequestURI)).Start()
}

// WSConnection is a wrapper interface for the needed functions of the websocket.Conn
// It is introduced for testability of the WSHandler
type WSConnection interface {
	Close()
	Send(bytes []byte) (err error)
	Receive(bytes *[]byte) (err error)
}

// wsconnImpl is a Wrapper of the websocket.Conn
// implementing the interface WSConn for better testability
type wsconn struct {
	*websocket.Conn
}

// Close the connection.
func (conn *wsconn) Close() {
	conn.Conn.Close()
}

// Send bytes through the connection and possibly return an error.
func (conn *wsconn) Send(bytes []byte) error {
	return conn.WriteMessage(websocket.BinaryMessage, bytes)
}

// Receive bytes through the connection and possibly return an error.
func (conn *wsconn) Receive(bytes *[]byte) (err error) {
	_, *bytes, err = conn.ReadMessage()
	return err
}

// WebSocket struct represents a websocket.
type WebSocket struct {
	*WSHandler
	WSConnection
	applicationID string
	userID        string
	sendChannel   chan []byte
	receivers     map[protocol.Path]*Receiver
}

// NewWebSocket returns a new WebSocket.
func NewWebSocket(handler *WSHandler, wsConn WSConnection, userID string) *WebSocket {
	return &WebSocket{
		WSHandler:     handler,
		WSConnection:  wsConn,
		applicationID: xid.New().String(),
		userID:        userID,
		sendChannel:   make(chan []byte, 10),
		receivers:     make(map[protocol.Path]*Receiver),
	}
}

// Start the WebSocket (the send and receive loops).
// It is implementing the service.startable interface.
func (ws *WebSocket) Start() error {
	ws.sendConnectionMessage()
	go ws.sendLoop()
	ws.receiveLoop()
	return nil
}

func (ws *WebSocket) sendLoop() {
	for raw := range ws.sendChannel {
		if !ws.checkAccess(raw) {
			continue
		}
		if err := ws.Send(raw); err != nil {
			logger.WithFields(log.Fields{
				"userId":        ws.userID,
				"applicationID": ws.applicationID,
				"totalSize":     len(raw),
				"actualContent": string(raw),
			}).Error("Could not send")
			ws.cleanAndClose()
			break
		}
	}
}

func (ws *WebSocket) checkAccess(raw []byte) bool {
	if raw[0] == byte('/') {
		path := getPathFromRawMessage(raw)

		logger.WithFields(log.Fields{
			"userID": ws.userID,
			"path":   path,
		}).Debug("Received msg")

		return len(path) == 0 || ws.accessManager.IsAllowed(auth.READ, ws.userID, path)

	}
	return true
}

func getPathFromRawMessage(raw []byte) protocol.Path {
	i := strings.Index(string(raw), ",")
	return protocol.Path(raw[:i])
}

func (ws *WebSocket) receiveLoop() {
	var message []byte
	for {
		err := ws.Receive(&message)
		if err != nil {

			logger.WithFields(log.Fields{
				"applicationID": ws.applicationID,
			}).Debug("Closed connnection by application")

			ws.cleanAndClose()
			break
		}

		//protocol.Debug("websocket_connector, raw message received: %v", string(message))
		cmd, err := protocol.ParseCmd(message)
		if err != nil {
			ws.sendError(protocol.ERROR_BAD_REQUEST, "error parsing command. %v", err.Error())
			continue
		}
		switch cmd.Name {
		case protocol.CmdSend:
			ws.handleSendCmd(cmd)
		case protocol.CmdReceive:
			ws.handleReceiveCmd(cmd)
		case protocol.CmdCancel:
			ws.handleCancelCmd(cmd)
		default:
			ws.sendError(protocol.ERROR_BAD_REQUEST, "unknown command %v", cmd.Name)
		}
	}
}

func (ws *WebSocket) sendConnectionMessage() {
	n := &protocol.NotificationMessage{
		Name: protocol.SUCCESS_CONNECTED,
		Arg:  "You are connected to the server.",
		Json: fmt.Sprintf(`{"ApplicationId": "%s", "UserId": "%s", "Time": "%s"}`, ws.applicationID, ws.userID, time.Now().Format(time.RFC3339)),
	}
	ws.sendChannel <- n.Bytes()
}

func (ws *WebSocket) handleReceiveCmd(cmd *protocol.Cmd) {
	rec, err := NewReceiverFromCmd(
		ws.applicationID,
		cmd,
		ws.sendChannel,
		ws.router,
		ws.userID,
	)
	if err != nil {
		logger.WithError(err).Error("Client error in handleReceiveCmd")
		ws.sendError(protocol.ERROR_BAD_REQUEST, err.Error())
		return
	}
	ws.receivers[rec.path] = rec
	rec.Start()
}

func (ws *WebSocket) handleCancelCmd(cmd *protocol.Cmd) {
	if len(cmd.Arg) == 0 {
		ws.sendError(protocol.ERROR_BAD_REQUEST, "- command requires a path argument, but none given")
		return
	}
	path := protocol.Path(cmd.Arg)
	rec, exist := ws.receivers[path]
	if exist {
		rec.Stop()
		delete(ws.receivers, path)
	}
}

func (ws *WebSocket) handleSendCmd(cmd *protocol.Cmd) {
	logger.WithFields(log.Fields{
		"cmd": string(cmd.Bytes()),
	}).Debug("Sending ")

	if len(cmd.Arg) == 0 {
		ws.sendError(protocol.ERROR_BAD_REQUEST, "send command requires a path argument, but none given")
		return
	}

	args := strings.SplitN(cmd.Arg, " ", 2)
	msg := &protocol.Message{
		Path:          protocol.Path(args[0]),
		ApplicationID: ws.applicationID,
		UserID:        ws.userID,
		HeaderJSON:    cmd.HeaderJSON,
		Body:          cmd.Body,
	}

	ws.router.HandleMessage(msg)

	ws.sendOK(protocol.SUCCESS_SEND, "")
}

func (ws *WebSocket) cleanAndClose() {

	logger.WithFields(log.Fields{
		"applicationID": ws.applicationID,
	}).Debug("Closing applicationId")

	for path, rec := range ws.receivers {
		rec.Stop()
		delete(ws.receivers, path)
	}

	ws.Close()
}

func (ws *WebSocket) sendError(name string, argPattern string, params ...interface{}) {
	n := &protocol.NotificationMessage{
		Name:    name,
		Arg:     fmt.Sprintf(argPattern, params...),
		IsError: true,
	}
	ws.sendChannel <- n.Bytes()
}

func (ws *WebSocket) sendOK(name string, argPattern string, params ...interface{}) {
	n := &protocol.NotificationMessage{
		Name:    name,
		Arg:     fmt.Sprintf(argPattern, params...),
		IsError: false,
	}
	ws.sendChannel <- n.Bytes()
}

// Extracts the userID out of an URI or empty string if format not met
// Example:
// 		http://example.com/user/user01/ -> user01
// 		http://example.com/user/ -> ""
func extractUserID(uri string) string {
	uriParts := strings.SplitN(uri, "/user/", 2)
	if len(uriParts) != 2 {
		return ""
	}
	return uriParts[1]
}
<commit_msg>check slice index before access<commit_after>package websocket

import (
	"github.com/smancke/guble/protocol"
	"github.com/smancke/guble/server/auth"
	"github.com/smancke/guble/server/router"

	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/websocket"
	"github.com/rs/xid"

	"fmt"
	"net/http"
	"strings"
	"time"
)

var webSocketUpgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true },
}

// WSHandler is a struct used for handling websocket connections on a certain prefix.
type WSHandler struct {
	router        router.Router
	prefix        string
	accessManager auth.AccessManager
}

// NewWSHandler returns a new WSHandler.
func NewWSHandler(router router.Router, prefix string) (*WSHandler, error) {
	accessManager, err := router.AccessManager()
	if err != nil {
		return nil, err
	}
	return &WSHandler{
		router:        router,
		prefix:        prefix,
		accessManager: accessManager,
	}, nil
}

// GetPrefix returns the prefix.
// It is a part of the service.endpoint implementation.
func (handler *WSHandler) GetPrefix() string {
	return handler.prefix
}

// ServeHTTP is an http.Handler.
// It is a part of the service.endpoint implementation.
func (handler *WSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c, err := webSocketUpgrader.Upgrade(w, r, nil)
	if err != nil {
		logger.WithError(err).Error("Error on upgrading to websocket")
		return
	}
	defer c.Close()

	NewWebSocket(handler, &wsconn{c}, extractUserID(r.RequestURI)).Start()
}

// WSConnection is a wrapper interface for the needed functions of the websocket.Conn
// It is introduced for testability of the WSHandler
type WSConnection interface {
	Close()
	Send(bytes []byte) (err error)
	Receive(bytes *[]byte) (err error)
}

// wsconnImpl is a Wrapper of the websocket.Conn
// implementing the interface WSConn for better testability
type wsconn struct {
	*websocket.Conn
}

// Close the connection.
func (conn *wsconn) Close() {
	conn.Conn.Close()
}

// Send bytes through the connection and possibly return an error.
func (conn *wsconn) Send(bytes []byte) error {
	return conn.WriteMessage(websocket.BinaryMessage, bytes)
}

// Receive bytes through the connection and possibly return an error.
func (conn *wsconn) Receive(bytes *[]byte) (err error) {
	_, *bytes, err = conn.ReadMessage()
	return err
}

// WebSocket struct represents a websocket.
type WebSocket struct {
	*WSHandler
	WSConnection
	applicationID string
	userID        string
	sendChannel   chan []byte
	receivers     map[protocol.Path]*Receiver
}

// NewWebSocket returns a new WebSocket.
func NewWebSocket(handler *WSHandler, wsConn WSConnection, userID string) *WebSocket {
	return &WebSocket{
		WSHandler:     handler,
		WSConnection:  wsConn,
		applicationID: xid.New().String(),
		userID:        userID,
		sendChannel:   make(chan []byte, 10),
		receivers:     make(map[protocol.Path]*Receiver),
	}
}

// Start the WebSocket (the send and receive loops).
// It is implementing the service.startable interface.
func (ws *WebSocket) Start() error {
	ws.sendConnectionMessage()
	go ws.sendLoop()
	ws.receiveLoop()
	return nil
}

func (ws *WebSocket) sendLoop() {
	for raw := range ws.sendChannel {
		if !ws.checkAccess(raw) {
			continue
		}
		if err := ws.Send(raw); err != nil {
			logger.WithFields(log.Fields{
				"userId":        ws.userID,
				"applicationID": ws.applicationID,
				"totalSize":     len(raw),
				"actualContent": string(raw),
			}).Error("Could not send")
			ws.cleanAndClose()
			break
		}
	}
}

func (ws *WebSocket) checkAccess(raw []byte) bool {
	if len(raw) > 0 && raw[0] == byte('/') {
		path := getPathFromRawMessage(raw)

		logger.WithFields(log.Fields{
			"userID": ws.userID,
			"path":   path,
		}).Debug("Received msg")

		return len(path) == 0 || ws.accessManager.IsAllowed(auth.READ, ws.userID, path)

	}
	return true
}

func getPathFromRawMessage(raw []byte) protocol.Path {
	i := strings.Index(string(raw), ",")
	return protocol.Path(raw[:i])
}

func (ws *WebSocket) receiveLoop() {
	var message []byte
	for {
		err := ws.Receive(&message)
		if err != nil {

			logger.WithFields(log.Fields{
				"applicationID": ws.applicationID,
			}).Debug("Closed connnection by application")

			ws.cleanAndClose()
			break
		}

		//protocol.Debug("websocket_connector, raw message received: %v", string(message))
		cmd, err := protocol.ParseCmd(message)
		if err != nil {
			ws.sendError(protocol.ERROR_BAD_REQUEST, "error parsing command. %v", err.Error())
			continue
		}
		switch cmd.Name {
		case protocol.CmdSend:
			ws.handleSendCmd(cmd)
		case protocol.CmdReceive:
			ws.handleReceiveCmd(cmd)
		case protocol.CmdCancel:
			ws.handleCancelCmd(cmd)
		default:
			ws.sendError(protocol.ERROR_BAD_REQUEST, "unknown command %v", cmd.Name)
		}
	}
}

func (ws *WebSocket) sendConnectionMessage() {
	n := &protocol.NotificationMessage{
		Name: protocol.SUCCESS_CONNECTED,
		Arg:  "You are connected to the server.",
		Json: fmt.Sprintf(`{"ApplicationId": "%s", "UserId": "%s", "Time": "%s"}`, ws.applicationID, ws.userID, time.Now().Format(time.RFC3339)),
	}
	ws.sendChannel <- n.Bytes()
}

func (ws *WebSocket) handleReceiveCmd(cmd *protocol.Cmd) {
	rec, err := NewReceiverFromCmd(
		ws.applicationID,
		cmd,
		ws.sendChannel,
		ws.router,
		ws.userID,
	)
	if err != nil {
		logger.WithError(err).Error("Client error in handleReceiveCmd")
		ws.sendError(protocol.ERROR_BAD_REQUEST, err.Error())
		return
	}
	ws.receivers[rec.path] = rec
	rec.Start()
}

func (ws *WebSocket) handleCancelCmd(cmd *protocol.Cmd) {
	if len(cmd.Arg) == 0 {
		ws.sendError(protocol.ERROR_BAD_REQUEST, "- command requires a path argument, but none given")
		return
	}
	path := protocol.Path(cmd.Arg)
	rec, exist := ws.receivers[path]
	if exist {
		rec.Stop()
		delete(ws.receivers, path)
	}
}

func (ws *WebSocket) handleSendCmd(cmd *protocol.Cmd) {
	logger.WithFields(log.Fields{
		"cmd": string(cmd.Bytes()),
	}).Debug("Sending ")

	if len(cmd.Arg) == 0 {
		ws.sendError(protocol.ERROR_BAD_REQUEST, "send command requires a path argument, but none given")
		return
	}

	args := strings.SplitN(cmd.Arg, " ", 2)
	msg := &protocol.Message{
		Path:          protocol.Path(args[0]),
		ApplicationID: ws.applicationID,
		UserID:        ws.userID,
		HeaderJSON:    cmd.HeaderJSON,
		Body:          cmd.Body,
	}

	ws.router.HandleMessage(msg)

	ws.sendOK(protocol.SUCCESS_SEND, "")
}

func (ws *WebSocket) cleanAndClose() {

	logger.WithFields(log.Fields{
		"applicationID": ws.applicationID,
	}).Debug("Closing applicationId")

	for path, rec := range ws.receivers {
		rec.Stop()
		delete(ws.receivers, path)
	}

	ws.Close()
}

func (ws *WebSocket) sendError(name string, argPattern string, params ...interface{}) {
	n := &protocol.NotificationMessage{
		Name:    name,
		Arg:     fmt.Sprintf(argPattern, params...),
		IsError: true,
	}
	ws.sendChannel <- n.Bytes()
}

func (ws *WebSocket) sendOK(name string, argPattern string, params ...interface{}) {
	n := &protocol.NotificationMessage{
		Name:    name,
		Arg:     fmt.Sprintf(argPattern, params...),
		IsError: false,
	}
	ws.sendChannel <- n.Bytes()
}

// Extracts the userID out of an URI or empty string if format not met
// Example:
// 		http://example.com/user/user01/ -> user01
// 		http://example.com/user/ -> ""
func extractUserID(uri string) string {
	uriParts := strings.SplitN(uri, "/user/", 2)
	if len(uriParts) != 2 {
		return ""
	}
	return uriParts[1]
}
<|endoftext|>


<commit_before>// Copyright (C) 2013 Miquel Sabaté Solà
// This file is licensed under the MIT license.
// See the LICENSE file.

// This package encapsulates all the methods regarding the File Cache.
package fcache

import (
    "os"
    "fmt"
    "path"
    "time"
    "errors"
    "io/ioutil"
)

// This type contains some needed info that will be used when caching.
type Cache struct {
    // The directory
    Dir string

    // The expiration time to be set for each file.
    Expiration time.Duration

    // The permissions to be set when this cache creates new files.
    Permissions os.FileMode
}

// Internal: get whether the cache file is still hot (valid) or not.
//
// mod - The last modification time of the cache file.
//
// Returns true if the cache file is still valid, false otherwise.
func (c *Cache) isHot(mod time.Time) bool {
    elapsed := time.Now().Sub(mod)
    return c.Expiration > elapsed
}

// Get a pointer to an initialized Cache structure.
//
// dir        - The path to the cache directory. If the directory does not
//              exist, it will create a new directory with permissions 0644.
// expiration - The expiration time. That is, how many nanoseconds has to pass
//              by when a cache file is no longer considered valid.
// perm       - The permissions that the cache should operate in when creating
//              new files.
//
// Returns a Cache pointer that points to an initialized Cache structure. It
// will return nil if something goes wrong.
func NewCache(dir string, expiration time.Duration, perm os.FileMode) *Cache {
    // First of all, get the directory path straight.
    if _, err := os.Stat(dir); err != nil {
        if os.IsNotExist(err) {
            if err = os.MkdirAll(dir, perm); err != nil {
                fmt.Printf("Error: %v\n", err)
                return nil
            }
        } else {
            fmt.Printf("Error: %v\n", err)
            return nil
        }
    }

    // Now it's safe to create the cache.
    cache := new(Cache)
    cache.Dir = dir
    cache.Expiration = expiration
    cache.Permissions = perm
    return cache
}

// Set the contents for a cache file. If this file doesn't exist already, it
// will be created with permissions 0644.
//
// name     - The name of the file.
// contents - The contents that the cache file has to contain after calling
//            this function.
//
// Returns nil if everything was ok. Otherwise it will return an error.
func (c *Cache) Set(name string, contents []byte) error {
    url := path.Join(c.Dir, name)
    return ioutil.WriteFile(url, contents, c.Permissions)
}

// Get the contents of a valid cache file.
//
// name - The name of the file.
//
// Returns a slice of bytes and an error. The slice of bytes contain the
// contents of the cache file. The error is set to nil if everything was fine.
func (c *Cache) Get(name string) ([]byte, error) {
    url := path.Join(c.Dir, name)
    if fi, err := os.Stat(url); err == nil {
        if c.isHot(fi.ModTime()) {
            return ioutil.ReadFile(url)
        }
        // Remove this file, its time has expired.
        os.Remove(url)
    }
    return []byte{}, errors.New("miss.")
}

// Remove a cache file.
//
// name - The name of the file.
//
// Returns nil if everything was ok. Otherwise it will return an error.
func (c *Cache) Flush(name string) error {
    url := path.Join(c.Dir, name)
    return os.Remove(url)
}

// Remove all the files from the cache.
//
// Returns nil if everything was ok. Otherwise it will return an error.
func (c *Cache) FlushAll() error {
    url := path.Join(c.Dir)
    err := os.RemoveAll(url)
    if err == nil {
        err = os.MkdirAll(url, c.Permissions)
    }
    return err
}
<commit_msg>Removed and extra space<commit_after>// Copyright (C) 2013 Miquel Sabaté Solà
// This file is licensed under the MIT license.
// See the LICENSE file.

// This package encapsulates all the methods regarding the File Cache.
package fcache

import (
    "os"
    "fmt"
    "path"
    "time"
    "errors"
    "io/ioutil"
)

// This type contains some needed info that will be used when caching.
type Cache struct {
    // The directory
    Dir string

    // The expiration time to be set for each file.
    Expiration time.Duration

    // The permissions to be set when this cache creates new files.
    Permissions os.FileMode
}

// Internal: get whether the cache file is still hot (valid) or not.
//
// mod - The last modification time of the cache file.
//
// Returns true if the cache file is still valid, false otherwise.
func (c *Cache) isHot(mod time.Time) bool {
    elapsed := time.Now().Sub(mod)
    return c.Expiration > elapsed
}

// Get a pointer to an initialized Cache structure.
//
// dir        - The path to the cache directory. If the directory does not
//              exist, it will create a new directory with permissions 0644.
// expiration - The expiration time. That is, how many nanoseconds has to pass
//              by when a cache file is no longer considered valid.
// perm       - The permissions that the cache should operate in when creating
//              new files.
//
// Returns a Cache pointer that points to an initialized Cache structure. It
// will return nil if something goes wrong.
func NewCache(dir string, expiration time.Duration, perm os.FileMode) *Cache {
    // First of all, get the directory path straight.
    if _, err := os.Stat(dir); err != nil {
        if os.IsNotExist(err) {
            if err = os.MkdirAll(dir, perm); err != nil {
                fmt.Printf("Error: %v\n", err)
                return nil
            }
        } else {
            fmt.Printf("Error: %v\n", err)
            return nil
        }
    }

    // Now it's safe to create the cache.
    cache := new(Cache)
    cache.Dir = dir
    cache.Expiration = expiration
    cache.Permissions = perm
    return cache
}

// Set the contents for a cache file. If this file doesn't exist already, it
// will be created with permissions 0644.
//
// name     - The name of the file.
// contents - The contents that the cache file has to contain after calling
//            this function.
//
// Returns nil if everything was ok. Otherwise it will return an error.
func (c *Cache) Set(name string, contents []byte) error {
    url := path.Join(c.Dir, name)
    return ioutil.WriteFile(url, contents, c.Permissions)
}

// Get the contents of a valid cache file.
//
// name - The name of the file.
//
// Returns a slice of bytes and an error. The slice of bytes contain the
// contents of the cache file. The error is set to nil if everything was fine.
func (c *Cache) Get(name string) ([]byte, error) {
    url := path.Join(c.Dir, name)
    if fi, err := os.Stat(url); err == nil {
        if c.isHot(fi.ModTime()) {
            return ioutil.ReadFile(url)
        }
        // Remove this file, its time has expired.
        os.Remove(url)
    }
    return []byte{}, errors.New("miss.")
}

// Remove a cache file.
//
// name - The name of the file.
//
// Returns nil if everything was ok. Otherwise it will return an error.
func (c *Cache) Flush(name string) error {
    url := path.Join(c.Dir, name)
    return os.Remove(url)
}

// Remove all the files from the cache.
//
// Returns nil if everything was ok. Otherwise it will return an error.
func (c *Cache) FlushAll() error {
    url := path.Join(c.Dir)
    err := os.RemoveAll(url)
    if err == nil {
        err = os.MkdirAll(url, c.Permissions)
    }
    return err
}
<|endoftext|>


<commit_before>// Copyright 2015 The Go 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 socktest provides utilities for socket testing.
package socktest

import (
	"fmt"
	"sync"
)

// A Switch represents a callpath point switch for socket system
// calls.
type Switch struct {
	once sync.Once

	fmu   sync.RWMutex
	fltab map[FilterType]Filter

	smu   sync.RWMutex
	sotab Sockets
	stats stats
}

func (sw *Switch) init() {
	sw.fltab = make(map[FilterType]Filter)
	sw.sotab = make(Sockets)
	sw.stats = make(stats)
}

// Stats returns a list of per-cookie socket statistics.
func (sw *Switch) Stats() []Stat {
	var st []Stat
	sw.smu.RLock()
	for _, s := range sw.stats {
		ns := *s
		st = append(st, ns)
	}
	sw.smu.RUnlock()
	return st
}

// Sockets returns mappings of socket descriptor to socket status.
func (sw *Switch) Sockets() Sockets {
	sw.smu.RLock()
	tab := make(Sockets, len(sw.sotab))
	for i, s := range sw.sotab {
		tab[i] = s
	}
	sw.smu.RUnlock()
	return tab
}

// A Cookie represents a 3-tuple of a socket; address family, socket
// type and protocol number.
type Cookie uint64

// Family returns an address family.
func (c Cookie) Family() int { return int(c >> 48) }

// Type returns a socket type.
func (c Cookie) Type() int { return int(c << 16 >> 32) }

// Protocol returns a protocol number.
func (c Cookie) Protocol() int { return int(c & 0xff) }

func cookie(family, sotype, proto int) Cookie {
	return Cookie(family)<<48 | Cookie(sotype)&0xffffffff<<16 | Cookie(proto)&0xff
}

// A Status represents the status of a socket.
type Status struct {
	Cookie    Cookie
	Err       error // error status of socket system call
	SocketErr error // error status of socket by SO_ERROR
}

func (so Status) String() string {
	return fmt.Sprintf("(%s, %s, %s): syscallerr=%v, socketerr=%v", familyString(so.Cookie.Family()), typeString(so.Cookie.Type()), protocolString(so.Cookie.Protocol()), so.Err, so.SocketErr)
}

// A Stat represents a per-cookie socket statistics.
type Stat struct {
	Family   int // address family
	Type     int // socket type
	Protocol int // protocol number

	Opened    uint64 // number of sockets opened
	Connected uint64 // number of sockets connected
	Listened  uint64 // number of sockets listened
	Accepted  uint64 // number of sockets accepted
	Closed    uint64 // number of sockets closed

	OpenFailed    uint64 // number of sockets open failed
	ConnectFailed uint64 // number of sockets connect failed
	ListenFailed  uint64 // number of sockets listen failed
	AcceptFailed  uint64 // number of sockets accept failed
	CloseFailed   uint64 // number of sockets close failed
}

func (st Stat) String() string {
	return fmt.Sprintf("(%s, %s, %s): opened=%d, connected=%d, listened=%d, accepted=%d, closed=%d, openfailed=%d, connectfailed=%d, listenfailed=%d, acceptfailed=%d, closefailed=%d", familyString(st.Family), typeString(st.Type), protocolString(st.Protocol), st.Opened, st.Connected, st.Listened, st.Accepted, st.Closed, st.OpenFailed, st.ConnectFailed, st.ListenFailed, st.AcceptFailed, st.CloseFailed)
}

type stats map[Cookie]*Stat

func (st stats) getLocked(c Cookie) *Stat {
	s, ok := st[c]
	if !ok {
		s = &Stat{Family: c.Family(), Type: c.Type(), Protocol: c.Protocol()}
		st[c] = s
	}
	return s
}

// A FilterType represents a filter type.
type FilterType int

const (
	FilterSocket        FilterType = iota // for Socket
	FilterConnect                         // for Connect or ConnectEx
	FilterListen                          // for Listen
	FilterAccept                          // for Accept or Accept4
	FilterGetsockoptInt                   // for GetsockoptInt
	FilterClose                           // for Close or Closesocket
)

// A Filter represents a socket system call filter.
//
// It will only be executed before a system call for a socket that has
// an entry in internal table.
// If the filter returns a non-nil error, the execution of system call
// will be canceled and the system call function returns the non-nil
// error.
// It can return a non-nil AfterFilter for filtering after the
// execution of the system call.
type Filter func(*Status) (AfterFilter, error)

func (f Filter) apply(st *Status) (AfterFilter, error) {
	if f == nil {
		return nil, nil
	}
	return f(st)
}

// An AfterFilter represents a socket system call filter after an
// execution of a system call.
//
// It will only be executed after a system call for a socket that has
// an entry in internal table.
// If the filter returns a non-nil error, the system call function
// returns the non-nil error.
type AfterFilter func(*Status) error

func (f AfterFilter) apply(st *Status) error {
	if f == nil {
		return nil
	}
	return f(st)
}

// Set deploys the socket system call filter f for the filter type t.
func (sw *Switch) Set(t FilterType, f Filter) {
	sw.once.Do(sw.init)
	sw.fmu.Lock()
	sw.fltab[t] = f
	sw.fmu.Unlock()
}
<commit_msg>net/internal/socktest: simplify log message format<commit_after>// Copyright 2015 The Go 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 socktest provides utilities for socket testing.
package socktest

import (
	"fmt"
	"sync"
)

// A Switch represents a callpath point switch for socket system
// calls.
type Switch struct {
	once sync.Once

	fmu   sync.RWMutex
	fltab map[FilterType]Filter

	smu   sync.RWMutex
	sotab Sockets
	stats stats
}

func (sw *Switch) init() {
	sw.fltab = make(map[FilterType]Filter)
	sw.sotab = make(Sockets)
	sw.stats = make(stats)
}

// Stats returns a list of per-cookie socket statistics.
func (sw *Switch) Stats() []Stat {
	var st []Stat
	sw.smu.RLock()
	for _, s := range sw.stats {
		ns := *s
		st = append(st, ns)
	}
	sw.smu.RUnlock()
	return st
}

// Sockets returns mappings of socket descriptor to socket status.
func (sw *Switch) Sockets() Sockets {
	sw.smu.RLock()
	tab := make(Sockets, len(sw.sotab))
	for i, s := range sw.sotab {
		tab[i] = s
	}
	sw.smu.RUnlock()
	return tab
}

// A Cookie represents a 3-tuple of a socket; address family, socket
// type and protocol number.
type Cookie uint64

// Family returns an address family.
func (c Cookie) Family() int { return int(c >> 48) }

// Type returns a socket type.
func (c Cookie) Type() int { return int(c << 16 >> 32) }

// Protocol returns a protocol number.
func (c Cookie) Protocol() int { return int(c & 0xff) }

func cookie(family, sotype, proto int) Cookie {
	return Cookie(family)<<48 | Cookie(sotype)&0xffffffff<<16 | Cookie(proto)&0xff
}

// A Status represents the status of a socket.
type Status struct {
	Cookie    Cookie
	Err       error // error status of socket system call
	SocketErr error // error status of socket by SO_ERROR
}

func (so Status) String() string {
	return fmt.Sprintf("(%s, %s, %s): syscallerr=%v socketerr=%v", familyString(so.Cookie.Family()), typeString(so.Cookie.Type()), protocolString(so.Cookie.Protocol()), so.Err, so.SocketErr)
}

// A Stat represents a per-cookie socket statistics.
type Stat struct {
	Family   int // address family
	Type     int // socket type
	Protocol int // protocol number

	Opened    uint64 // number of sockets opened
	Connected uint64 // number of sockets connected
	Listened  uint64 // number of sockets listened
	Accepted  uint64 // number of sockets accepted
	Closed    uint64 // number of sockets closed

	OpenFailed    uint64 // number of sockets open failed
	ConnectFailed uint64 // number of sockets connect failed
	ListenFailed  uint64 // number of sockets listen failed
	AcceptFailed  uint64 // number of sockets accept failed
	CloseFailed   uint64 // number of sockets close failed
}

func (st Stat) String() string {
	return fmt.Sprintf("(%s, %s, %s): opened=%d connected=%d listened=%d accepted=%d closed=%d openfailed=%d connectfailed=%d listenfailed=%d acceptfailed=%d closefailed=%d", familyString(st.Family), typeString(st.Type), protocolString(st.Protocol), st.Opened, st.Connected, st.Listened, st.Accepted, st.Closed, st.OpenFailed, st.ConnectFailed, st.ListenFailed, st.AcceptFailed, st.CloseFailed)
}

type stats map[Cookie]*Stat

func (st stats) getLocked(c Cookie) *Stat {
	s, ok := st[c]
	if !ok {
		s = &Stat{Family: c.Family(), Type: c.Type(), Protocol: c.Protocol()}
		st[c] = s
	}
	return s
}

// A FilterType represents a filter type.
type FilterType int

const (
	FilterSocket        FilterType = iota // for Socket
	FilterConnect                         // for Connect or ConnectEx
	FilterListen                          // for Listen
	FilterAccept                          // for Accept or Accept4
	FilterGetsockoptInt                   // for GetsockoptInt
	FilterClose                           // for Close or Closesocket
)

// A Filter represents a socket system call filter.
//
// It will only be executed before a system call for a socket that has
// an entry in internal table.
// If the filter returns a non-nil error, the execution of system call
// will be canceled and the system call function returns the non-nil
// error.
// It can return a non-nil AfterFilter for filtering after the
// execution of the system call.
type Filter func(*Status) (AfterFilter, error)

func (f Filter) apply(st *Status) (AfterFilter, error) {
	if f == nil {
		return nil, nil
	}
	return f(st)
}

// An AfterFilter represents a socket system call filter after an
// execution of a system call.
//
// It will only be executed after a system call for a socket that has
// an entry in internal table.
// If the filter returns a non-nil error, the system call function
// returns the non-nil error.
type AfterFilter func(*Status) error

func (f AfterFilter) apply(st *Status) error {
	if f == nil {
		return nil
	}
	return f(st)
}

// Set deploys the socket system call filter f for the filter type t.
func (sw *Switch) Set(t FilterType, f Filter) {
	sw.once.Do(sw.init)
	sw.fmu.Lock()
	sw.fltab[t] = f
	sw.fmu.Unlock()
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package service

import (
	"time"
)

const (
	// RespondingTimeout is how long to wait for a service to be responding.
	RespondingTimeout = 2 * time.Minute

	// MaxNodesForEndpointsTests is the max number for testing endpoints.
	// Don't test with more than 3 nodes.
	// Many tests create an endpoint per node, in large clusters, this is
	// resource and time intensive.
	MaxNodesForEndpointsTests = 3

	// KubeProxyLagTimeout is the maximum time a kube-proxy daemon on a node is allowed
	// to not notice a Service update, such as type=NodePort.
	// TODO: This timeout should be O(10s), observed values are O(1m), 5m is very
	// liberal. Fix tracked in #20567.
	KubeProxyLagTimeout = 5 * time.Minute

	// KubeProxyEndpointLagTimeout is the maximum time a kube-proxy daemon on a node is allowed
	// to not notice an Endpoint update.
	KubeProxyEndpointLagTimeout = 30 * time.Second

	// LoadBalancerLagTimeoutDefault is the maximum time a load balancer is allowed to
	// not respond after creation.
	LoadBalancerLagTimeoutDefault = 2 * time.Minute

	// LoadBalancerLagTimeoutAWS is the delay between ELB creation and serving traffic
	// on AWS. A few minutes is typical, so use 10m.
	LoadBalancerLagTimeoutAWS = 10 * time.Minute

	// LoadBalancerCreateTimeoutDefault is the default time to wait for a load balancer to be created/modified.
	// TODO: once support ticket 21807001 is resolved, reduce this timeout back to something reasonable
	// Hideen - use GetServiceLoadBalancerCreateTimeout function instead.
	loadBalancerCreateTimeoutDefault = 10 * time.Minute
	// LoadBalancerCreateTimeoutLarge is the maximum time to wait for a load balancer to be created/modified.
	// Hideen - use GetServiceLoadBalancerCreateTimeout function instead.
	loadBalancerCreateTimeoutLarge = 45 * time.Minute

	// LoadBalancerPropagationTimeoutDefault is the default time to wait for pods to
	// be targeted by load balancers.
	// Hideen - use GetServiceLoadBalancerPropagationTimeout function instead.
	loadBalancerPropagationTimeoutDefault = 10 * time.Minute
	// LoadBalancerPropagationTimeoutLarge is the maximum time to wait for pods to
	// be targeted by load balancers.
	// Hideen - use GetServiceLoadBalancerPropagationTimeout function instead.
	loadBalancerPropagationTimeoutLarge = time.Hour

	// LoadBalancerCleanupTimeout is the time required by the loadbalancer to cleanup, proportional to numApps/Ing.
	// Bring the cleanup timeout back down to 5m once b/33588344 is resolved.
	LoadBalancerCleanupTimeout = 15 * time.Minute

	// LoadBalancerPollInterval is the interval value in which the loadbalancer polls.
	LoadBalancerPollInterval = 30 * time.Second

	// LargeClusterMinNodesNumber is the number of nodes which a large cluster consists of.
	LargeClusterMinNodesNumber = 100

	// TestTimeout is used for most polling/waiting activities
	TestTimeout = 60 * time.Second

	// ServiceEndpointsTimeout is the maximum time in which endpoints for the service should be created.
	ServiceEndpointsTimeout = 2 * time.Minute

	// ServiceReachabilityShortPollTimeout is the maximum time in which service must be reachable during polling.
	ServiceReachabilityShortPollTimeout = 2 * time.Minute
)
<commit_msg>bump e2e loadbalancer timeouts to 15m<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package service

import (
	"time"
)

const (
	// RespondingTimeout is how long to wait for a service to be responding.
	RespondingTimeout = 2 * time.Minute

	// MaxNodesForEndpointsTests is the max number for testing endpoints.
	// Don't test with more than 3 nodes.
	// Many tests create an endpoint per node, in large clusters, this is
	// resource and time intensive.
	MaxNodesForEndpointsTests = 3

	// KubeProxyLagTimeout is the maximum time a kube-proxy daemon on a node is allowed
	// to not notice a Service update, such as type=NodePort.
	// TODO: This timeout should be O(10s), observed values are O(1m), 5m is very
	// liberal. Fix tracked in #20567.
	KubeProxyLagTimeout = 5 * time.Minute

	// KubeProxyEndpointLagTimeout is the maximum time a kube-proxy daemon on a node is allowed
	// to not notice an Endpoint update.
	KubeProxyEndpointLagTimeout = 30 * time.Second

	// LoadBalancerLagTimeoutDefault is the maximum time a load balancer is allowed to
	// not respond after creation.
	LoadBalancerLagTimeoutDefault = 2 * time.Minute

	// LoadBalancerLagTimeoutAWS is the delay between ELB creation and serving traffic
	// on AWS. A few minutes is typical, so use 10m.
	LoadBalancerLagTimeoutAWS = 10 * time.Minute

	// LoadBalancerCreateTimeoutDefault is the default time to wait for a load balancer to be created/modified.
	// TODO: once support ticket 21807001 is resolved, reduce this timeout back to something reasonable
	// Hideen - use GetServiceLoadBalancerCreateTimeout function instead.
	loadBalancerCreateTimeoutDefault = 15 * time.Minute
	// LoadBalancerCreateTimeoutLarge is the maximum time to wait for a load balancer to be created/modified.
	// Hideen - use GetServiceLoadBalancerCreateTimeout function instead.
	loadBalancerCreateTimeoutLarge = 45 * time.Minute

	// LoadBalancerPropagationTimeoutDefault is the default time to wait for pods to
	// be targeted by load balancers.
	// Hideen - use GetServiceLoadBalancerPropagationTimeout function instead.
	loadBalancerPropagationTimeoutDefault = 10 * time.Minute
	// LoadBalancerPropagationTimeoutLarge is the maximum time to wait for pods to
	// be targeted by load balancers.
	// Hideen - use GetServiceLoadBalancerPropagationTimeout function instead.
	loadBalancerPropagationTimeoutLarge = time.Hour

	// LoadBalancerCleanupTimeout is the time required by the loadbalancer to cleanup, proportional to numApps/Ing.
	// Bring the cleanup timeout back down to 5m once b/33588344 is resolved.
	LoadBalancerCleanupTimeout = 15 * time.Minute

	// LoadBalancerPollInterval is the interval value in which the loadbalancer polls.
	LoadBalancerPollInterval = 30 * time.Second

	// LargeClusterMinNodesNumber is the number of nodes which a large cluster consists of.
	LargeClusterMinNodesNumber = 100

	// TestTimeout is used for most polling/waiting activities
	TestTimeout = 60 * time.Second

	// ServiceEndpointsTimeout is the maximum time in which endpoints for the service should be created.
	ServiceEndpointsTimeout = 2 * time.Minute

	// ServiceReachabilityShortPollTimeout is the maximum time in which service must be reachable during polling.
	ServiceReachabilityShortPollTimeout = 2 * time.Minute
)
<|endoftext|>


<commit_before>// Copyright 2013 The Gorilla WebSocket 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 (
	"strings"

	"fmt"

	"github.com/gorilla/websocket"
)

type OnMessage func(fromAddr string, msg []byte)

// Client is a middleman between the websocket connection and the hub.
type RequestMsg struct {
	// The websocket connection.
	conn *websocket.Conn
	msg  []byte
}

// hub maintains the set of active clients and broadcasts messages to the
// clients.
type Hub struct {
	// Registered clients.
	clients map[*Client]bool

	// Inbound messages from the clients.
	request chan *RequestMsg

	// Register requests from the clients.
	register chan *Client

	// Unregister requests from clients.
	unregister chan *Client
}

func newHub() *Hub {
	return &Hub{
		request:    make(chan *RequestMsg),
		register:   make(chan *Client),
		unregister: make(chan *Client),
		clients:    make(map[*Client]bool),
	}
}

func (h *Hub) sendMessageToAddr(sendToIP string, message []byte) {
	// TODO: make this a hashtable to avoid iterating over all clients
	for client := range h.clients {
		fmt.Println("Finding client to forward to...")
		clientIP := strings.Split(client.conn.RemoteAddr().String(), ":")[0]
		if clientIP == sendToIP {
			client.send <- message
			fmt.Println("...done")
			break
		}
	}
}

func (h *Hub) run(cb OnMessage) {
	for {
		select {
		case client := <-h.register:
			h.clients[client] = true
		case client := <-h.unregister:
			if _, ok := h.clients[client]; ok {
				delete(h.clients, client)
				close(client.send)
			}
		case req := <-h.request:
			cb(req.conn.RemoteAddr().String(), req.msg)
		}
	}
}
<commit_msg>check ports when comparing clients<commit_after>// Copyright 2013 The Gorilla WebSocket 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 (
	"fmt"

	"github.com/gorilla/websocket"
)

type OnMessage func(fromAddr string, msg []byte)

// Client is a middleman between the websocket connection and the hub.
type RequestMsg struct {
	// The websocket connection.
	conn *websocket.Conn
	msg  []byte
}

// hub maintains the set of active clients and broadcasts messages to the
// clients.
type Hub struct {
	// Registered clients.
	clients map[*Client]bool

	// Inbound messages from the clients.
	request chan *RequestMsg

	// Register requests from the clients.
	register chan *Client

	// Unregister requests from clients.
	unregister chan *Client
}

func newHub() *Hub {
	return &Hub{
		request:    make(chan *RequestMsg),
		register:   make(chan *Client),
		unregister: make(chan *Client),
		clients:    make(map[*Client]bool),
	}
}

func (h *Hub) sendMessageToAddr(sendToIP string, message []byte) {
	// TODO: make this a hashtable to avoid iterating over all clients
	for client := range h.clients {
		fmt.Println("Finding client to forward to...")
		if client.conn.RemoteAddr().String() == sendToIP {
			client.send <- message
			fmt.Println("...done")
			break
		}
	}
}

func (h *Hub) run(cb OnMessage) {
	for {
		select {
		case client := <-h.register:
			h.clients[client] = true
		case client := <-h.unregister:
			if _, ok := h.clients[client]; ok {
				delete(h.clients, client)
				close(client.send)
			}
		case req := <-h.request:
			cb(req.conn.RemoteAddr().String(), req.msg)
		}
	}
}
<|endoftext|>


<commit_before>package aws

import (
	"errors"
	"fmt"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
)

// How long to sleep if a limit-exceeded event happens
var routeTargetValidationError = errors.New("Error: more than 1 target specified. Only 1 of gateway_id" +
	"nat_gateway_id, instance_id, network_interface_id, route_table_id or" +
	"vpc_peering_connection_id is allowed.")

// AWS Route resource Schema declaration
func resourceAwsRoute() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsRouteCreate,
		Read:   resourceAwsRouteRead,
		Update: resourceAwsRouteUpdate,
		Delete: resourceAwsRouteDelete,
		Exists: resourceAwsRouteExists,

		Schema: map[string]*schema.Schema{
			"destination_cidr_block": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"destination_prefix_list_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"gateway_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"nat_gateway_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"instance_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"instance_owner_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"network_interface_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"origin": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"state": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"route_table_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"vpc_peering_connection_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
		},
	}
}

func resourceAwsRouteCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	var numTargets int
	var setTarget string
	allowedTargets := []string{
		"gateway_id",
		"nat_gateway_id",
		"instance_id",
		"network_interface_id",
		"vpc_peering_connection_id",
	}

	// Check if more than 1 target is specified
	for _, target := range allowedTargets {
		if len(d.Get(target).(string)) > 0 {
			numTargets++
			setTarget = target
		}
	}

	if numTargets > 1 {
		return routeTargetValidationError
	}

	createOpts := &ec2.CreateRouteInput{}
	// Formulate CreateRouteInput based on the target type
	switch setTarget {
	case "gateway_id":
		createOpts = &ec2.CreateRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			GatewayId:            aws.String(d.Get("gateway_id").(string)),
		}
	case "nat_gateway_id":
		createOpts = &ec2.CreateRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			NatGatewayId:         aws.String(d.Get("nat_gateway_id").(string)),
		}
	case "instance_id":
		createOpts = &ec2.CreateRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			InstanceId:           aws.String(d.Get("instance_id").(string)),
		}
	case "network_interface_id":
		createOpts = &ec2.CreateRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			NetworkInterfaceId:   aws.String(d.Get("network_interface_id").(string)),
		}
	case "vpc_peering_connection_id":
		createOpts = &ec2.CreateRouteInput{
			RouteTableId:           aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock:   aws.String(d.Get("destination_cidr_block").(string)),
			VpcPeeringConnectionId: aws.String(d.Get("vpc_peering_connection_id").(string)),
		}
	default:
		return fmt.Errorf("Error: invalid target type specified.")
	}
	log.Printf("[DEBUG] Route create config: %s", createOpts)

	// Create the route
	_, err := conn.CreateRoute(createOpts)
	if err != nil {
		return fmt.Errorf("Error creating route: %s", err)
	}

	route, err := findResourceRoute(conn, d.Get("route_table_id").(string), d.Get("destination_cidr_block").(string))
	if err != nil {
		return err
	}

	d.SetId(routeIDHash(d, route))

	return resourceAwsRouteRead(d, meta)
}

func resourceAwsRouteRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	route, err := findResourceRoute(conn, d.Get("route_table_id").(string), d.Get("destination_cidr_block").(string))
	if err != nil {
		return err
	}

	d.Set("destination_prefix_list_id", route.DestinationPrefixListId)
	d.Set("gateway_id", route.GatewayId)
	d.Set("nat_gateway_id", route.NatGatewayId)
	d.Set("instance_id", route.InstanceId)
	d.Set("instance_owner_id", route.InstanceOwnerId)
	d.Set("network_interface_id", route.NetworkInterfaceId)
	d.Set("origin", route.Origin)
	d.Set("state", route.State)
	d.Set("vpc_peering_connection_id", route.VpcPeeringConnectionId)

	return nil
}

func resourceAwsRouteUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	var numTargets int
	var setTarget string
	allowedTargets := []string{
		"gateway_id",
		"nat_gateway_id",
		"instance_id",
		"network_interface_id",
		"vpc_peering_connection_id",
	}
	replaceOpts := &ec2.ReplaceRouteInput{}

	// Check if more than 1 target is specified
	for _, target := range allowedTargets {
		if len(d.Get(target).(string)) > 0 {
			numTargets++
			setTarget = target
		}
	}

	if numTargets > 1 {
		return routeTargetValidationError
	}

	// Formulate ReplaceRouteInput based on the target type
	switch setTarget {
	case "gateway_id":
		replaceOpts = &ec2.ReplaceRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			GatewayId:            aws.String(d.Get("gateway_id").(string)),
		}
	case "nat_gateway_id":
		replaceOpts = &ec2.ReplaceRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			NatGatewayId:         aws.String(d.Get("nat_gateway_id").(string)),
		}
	case "instance_id":
		replaceOpts = &ec2.ReplaceRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			InstanceId:           aws.String(d.Get("instance_id").(string)),
			//NOOP: Ensure we don't blow away network interface id that is set after instance is launched
			NetworkInterfaceId: aws.String(d.Get("network_interface_id").(string)),
		}
	case "network_interface_id":
		replaceOpts = &ec2.ReplaceRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			NetworkInterfaceId:   aws.String(d.Get("network_interface_id").(string)),
		}
	case "vpc_peering_connection_id":
		replaceOpts = &ec2.ReplaceRouteInput{
			RouteTableId:           aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock:   aws.String(d.Get("destination_cidr_block").(string)),
			VpcPeeringConnectionId: aws.String(d.Get("vpc_peering_connection_id").(string)),
		}
	default:
		return fmt.Errorf("Error: invalid target type specified.")
	}
	log.Printf("[DEBUG] Route replace config: %s", replaceOpts)

	// Replace the route
	_, err := conn.ReplaceRoute(replaceOpts)
	if err != nil {
		return err
	}

	return nil
}

func resourceAwsRouteDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	deleteOpts := &ec2.DeleteRouteInput{
		RouteTableId:         aws.String(d.Get("route_table_id").(string)),
		DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
	}
	log.Printf("[DEBUG] Route delete opts: %s", deleteOpts)

	resp, err := conn.DeleteRoute(deleteOpts)
	log.Printf("[DEBUG] Route delete result: %s", resp)
	if err != nil {
		return err
	}

	d.SetId("")
	return nil
}

func resourceAwsRouteExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	conn := meta.(*AWSClient).ec2conn
	routeTableId := d.Get("route_table_id").(string)

	findOpts := &ec2.DescribeRouteTablesInput{
		RouteTableIds: []*string{&routeTableId},
	}

	res, err := conn.DescribeRouteTables(findOpts)
	if err != nil {
		return false, fmt.Errorf("Error while checking if route exists: %s", err)
	}

	if len(res.RouteTables) < 1 || res.RouteTables[0] == nil {
		log.Printf("[WARN] Route table %s is gone, so route does not exist.",
			routeTableId)
		return false, nil
	}

	cidr := d.Get("destination_cidr_block").(string)
	for _, route := range (*res.RouteTables[0]).Routes {
		if route.DestinationCidrBlock != nil && *route.DestinationCidrBlock == cidr {
			return true, nil
		}
	}

	return false, nil
}

// Create an ID for a route
func routeIDHash(d *schema.ResourceData, r *ec2.Route) string {
	return fmt.Sprintf("r-%s%d", d.Get("route_table_id").(string), hashcode.String(*r.DestinationCidrBlock))
}

// Helper: retrieve a route
func findResourceRoute(conn *ec2.EC2, rtbid string, cidr string) (*ec2.Route, error) {
	routeTableID := rtbid

	findOpts := &ec2.DescribeRouteTablesInput{
		RouteTableIds: []*string{&routeTableID},
	}

	resp, err := conn.DescribeRouteTables(findOpts)
	if err != nil {
		return nil, err
	}

	if len(resp.RouteTables) < 1 || resp.RouteTables[0] == nil {
		return nil, fmt.Errorf("Route table %s is gone, so route does not exist.",
			routeTableID)
	}

	for _, route := range (*resp.RouteTables[0]).Routes {
		if *route.DestinationCidrBlock == cidr {
			return route, nil
		}
	}

	return nil, fmt.Errorf(`
error finding matching route for Route table (%s) and destination CIDR block (%s)`,
		rtbid, cidr)
}
<commit_msg>Use resource.Retry for route creation and deletion (#6225)<commit_after>package aws

import (
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

// How long to sleep if a limit-exceeded event happens
var routeTargetValidationError = errors.New("Error: more than 1 target specified. Only 1 of gateway_id" +
	"nat_gateway_id, instance_id, network_interface_id, route_table_id or" +
	"vpc_peering_connection_id is allowed.")

// AWS Route resource Schema declaration
func resourceAwsRoute() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsRouteCreate,
		Read:   resourceAwsRouteRead,
		Update: resourceAwsRouteUpdate,
		Delete: resourceAwsRouteDelete,
		Exists: resourceAwsRouteExists,

		Schema: map[string]*schema.Schema{
			"destination_cidr_block": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"destination_prefix_list_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"gateway_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"nat_gateway_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"instance_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"instance_owner_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"network_interface_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"origin": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"state": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"route_table_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"vpc_peering_connection_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
		},
	}
}

func resourceAwsRouteCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	var numTargets int
	var setTarget string
	allowedTargets := []string{
		"gateway_id",
		"nat_gateway_id",
		"instance_id",
		"network_interface_id",
		"vpc_peering_connection_id",
	}

	// Check if more than 1 target is specified
	for _, target := range allowedTargets {
		if len(d.Get(target).(string)) > 0 {
			numTargets++
			setTarget = target
		}
	}

	if numTargets > 1 {
		return routeTargetValidationError
	}

	createOpts := &ec2.CreateRouteInput{}
	// Formulate CreateRouteInput based on the target type
	switch setTarget {
	case "gateway_id":
		createOpts = &ec2.CreateRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			GatewayId:            aws.String(d.Get("gateway_id").(string)),
		}
	case "nat_gateway_id":
		createOpts = &ec2.CreateRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			NatGatewayId:         aws.String(d.Get("nat_gateway_id").(string)),
		}
	case "instance_id":
		createOpts = &ec2.CreateRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			InstanceId:           aws.String(d.Get("instance_id").(string)),
		}
	case "network_interface_id":
		createOpts = &ec2.CreateRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			NetworkInterfaceId:   aws.String(d.Get("network_interface_id").(string)),
		}
	case "vpc_peering_connection_id":
		createOpts = &ec2.CreateRouteInput{
			RouteTableId:           aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock:   aws.String(d.Get("destination_cidr_block").(string)),
			VpcPeeringConnectionId: aws.String(d.Get("vpc_peering_connection_id").(string)),
		}
	default:
		return fmt.Errorf("Error: invalid target type specified.")
	}
	log.Printf("[DEBUG] Route create config: %s", createOpts)

	// Create the route
	var err error

	err = resource.Retry(2*time.Minute, func() *resource.RetryError {
		_, err = conn.CreateRoute(createOpts)

		if err != nil {
			ec2err, ok := err.(awserr.Error)
			if !ok {
				return resource.NonRetryableError(err)
			}
			if ec2err.Code() == "InvalidParameterException" {
				log.Printf("[DEBUG] Trying to create route again: %q", ec2err.Message())
				return resource.RetryableError(err)
			}

			return resource.NonRetryableError(err)
		}

		return nil
	})
	if err != nil {
		return fmt.Errorf("Error creating route: %s", err)
	}

	route, err := findResourceRoute(conn, d.Get("route_table_id").(string), d.Get("destination_cidr_block").(string))
	if err != nil {
		return err
	}

	d.SetId(routeIDHash(d, route))

	return resourceAwsRouteRead(d, meta)
}

func resourceAwsRouteRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	route, err := findResourceRoute(conn, d.Get("route_table_id").(string), d.Get("destination_cidr_block").(string))
	if err != nil {
		return err
	}

	d.Set("destination_prefix_list_id", route.DestinationPrefixListId)
	d.Set("gateway_id", route.GatewayId)
	d.Set("nat_gateway_id", route.NatGatewayId)
	d.Set("instance_id", route.InstanceId)
	d.Set("instance_owner_id", route.InstanceOwnerId)
	d.Set("network_interface_id", route.NetworkInterfaceId)
	d.Set("origin", route.Origin)
	d.Set("state", route.State)
	d.Set("vpc_peering_connection_id", route.VpcPeeringConnectionId)

	return nil
}

func resourceAwsRouteUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	var numTargets int
	var setTarget string
	allowedTargets := []string{
		"gateway_id",
		"nat_gateway_id",
		"instance_id",
		"network_interface_id",
		"vpc_peering_connection_id",
	}
	replaceOpts := &ec2.ReplaceRouteInput{}

	// Check if more than 1 target is specified
	for _, target := range allowedTargets {
		if len(d.Get(target).(string)) > 0 {
			numTargets++
			setTarget = target
		}
	}

	if numTargets > 1 {
		return routeTargetValidationError
	}

	// Formulate ReplaceRouteInput based on the target type
	switch setTarget {
	case "gateway_id":
		replaceOpts = &ec2.ReplaceRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			GatewayId:            aws.String(d.Get("gateway_id").(string)),
		}
	case "nat_gateway_id":
		replaceOpts = &ec2.ReplaceRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			NatGatewayId:         aws.String(d.Get("nat_gateway_id").(string)),
		}
	case "instance_id":
		replaceOpts = &ec2.ReplaceRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			InstanceId:           aws.String(d.Get("instance_id").(string)),
			//NOOP: Ensure we don't blow away network interface id that is set after instance is launched
			NetworkInterfaceId: aws.String(d.Get("network_interface_id").(string)),
		}
	case "network_interface_id":
		replaceOpts = &ec2.ReplaceRouteInput{
			RouteTableId:         aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
			NetworkInterfaceId:   aws.String(d.Get("network_interface_id").(string)),
		}
	case "vpc_peering_connection_id":
		replaceOpts = &ec2.ReplaceRouteInput{
			RouteTableId:           aws.String(d.Get("route_table_id").(string)),
			DestinationCidrBlock:   aws.String(d.Get("destination_cidr_block").(string)),
			VpcPeeringConnectionId: aws.String(d.Get("vpc_peering_connection_id").(string)),
		}
	default:
		return fmt.Errorf("Error: invalid target type specified.")
	}
	log.Printf("[DEBUG] Route replace config: %s", replaceOpts)

	// Replace the route
	_, err := conn.ReplaceRoute(replaceOpts)
	if err != nil {
		return err
	}

	return nil
}

func resourceAwsRouteDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	deleteOpts := &ec2.DeleteRouteInput{
		RouteTableId:         aws.String(d.Get("route_table_id").(string)),
		DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
	}
	log.Printf("[DEBUG] Route delete opts: %s", deleteOpts)

	var err error
	err = resource.Retry(5*time.Minute, func() *resource.RetryError {
		log.Printf("[DEBUG] Trying to delete route with opts %s", deleteOpts)
		resp, err := conn.DeleteRoute(deleteOpts)
		log.Printf("[DEBUG] Route delete result: %s", resp)

		if err == nil {
			return nil
		}

		ec2err, ok := err.(awserr.Error)
		if !ok {
			return resource.NonRetryableError(err)
		}
		if ec2err.Code() == "InvalidParameterException" {
			log.Printf("[DEBUG] Trying to delete route again: %q",
				ec2err.Message())
			return resource.RetryableError(err)
		}

		return resource.NonRetryableError(err)
	})

	if err != nil {
		return err
	}

	d.SetId("")
	return nil
}

func resourceAwsRouteExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	conn := meta.(*AWSClient).ec2conn
	routeTableId := d.Get("route_table_id").(string)

	findOpts := &ec2.DescribeRouteTablesInput{
		RouteTableIds: []*string{&routeTableId},
	}

	res, err := conn.DescribeRouteTables(findOpts)
	if err != nil {
		return false, fmt.Errorf("Error while checking if route exists: %s", err)
	}

	if len(res.RouteTables) < 1 || res.RouteTables[0] == nil {
		log.Printf("[WARN] Route table %s is gone, so route does not exist.",
			routeTableId)
		return false, nil
	}

	cidr := d.Get("destination_cidr_block").(string)
	for _, route := range (*res.RouteTables[0]).Routes {
		if route.DestinationCidrBlock != nil && *route.DestinationCidrBlock == cidr {
			return true, nil
		}
	}

	return false, nil
}

// Create an ID for a route
func routeIDHash(d *schema.ResourceData, r *ec2.Route) string {
	return fmt.Sprintf("r-%s%d", d.Get("route_table_id").(string), hashcode.String(*r.DestinationCidrBlock))
}

// Helper: retrieve a route
func findResourceRoute(conn *ec2.EC2, rtbid string, cidr string) (*ec2.Route, error) {
	routeTableID := rtbid

	findOpts := &ec2.DescribeRouteTablesInput{
		RouteTableIds: []*string{&routeTableID},
	}

	resp, err := conn.DescribeRouteTables(findOpts)
	if err != nil {
		return nil, err
	}

	if len(resp.RouteTables) < 1 || resp.RouteTables[0] == nil {
		return nil, fmt.Errorf("Route table %s is gone, so route does not exist.",
			routeTableID)
	}

	for _, route := range (*resp.RouteTables[0]).Routes {
		if *route.DestinationCidrBlock == cidr {
			return route, nil
		}
	}

	return nil, fmt.Errorf(`
error finding matching route for Route table (%s) and destination CIDR block (%s)`,
		rtbid, cidr)
}
<|endoftext|>


<commit_before>package sakuracloud

import (
	"fmt"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/yamamoto-febc/libsacloud/api"
	"testing"
)

func TestAccSakuraCloudDNSDataSource_Basic(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:                  func() { testAccPreCheck(t) },
		Providers:                 testAccProviders,
		PreventPostDestroyRefresh: true,
		CheckDestroy:              testAccCheckSakuraCloudDNSDataSourceDestroy,

		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckSakuraCloudDataSourceDNSBase,
				Check:  testAccCheckSakuraCloudDNSDataSourceID("sakuracloud_dns.foobar"),
			},
			resource.TestStep{
				Config: testAccCheckSakuraCloudDataSourceDNSConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSakuraCloudDNSDataSourceID("data.sakuracloud_dns.foobar"),
					resource.TestCheckResourceAttr("data.sakuracloud_dns.foobar", "zone", "test-terraform-sakuracloud.com"),
					resource.TestCheckResourceAttr("data.sakuracloud_dns.foobar", "description", "description_test"),
					resource.TestCheckResourceAttr("data.sakuracloud_dns.foobar", "tags.#", "3"),
					resource.TestCheckResourceAttr("data.sakuracloud_dns.foobar", "tags.0", "tag1"),
					resource.TestCheckResourceAttr("data.sakuracloud_dns.foobar", "tags.1", "tag2"),
					resource.TestCheckResourceAttr("data.sakuracloud_dns.foobar", "tags.2", "tag3"),
				),
			},
			resource.TestStep{
				Destroy: true,
				Config:  testAccCheckSakuraCloudDataSourceDNSConfig_With_Tag,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSakuraCloudDNSDataSourceID("data.sakuracloud_dns.foobar"),
				),
			},
			resource.TestStep{
				Destroy: true,
				Config:  testAccCheckSakuraCloudDataSourceDNSConfig_NotExists,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSakuraCloudDNSDataSourceNotExists("data.sakuracloud_dns.foobar"),
				),
			},
			resource.TestStep{
				Destroy: true,
				Config:  testAccCheckSakuraCloudDataSourceDNSConfig_With_NotExists_Tag,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSakuraCloudDNSDataSourceNotExists("data.sakuracloud_dns.foobar"),
				),
			},
		},
	})
}

func testAccCheckSakuraCloudDNSDataSourceID(n string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Can't find DNS data source: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("DNS data source ID not set")
		}
		return nil
	}
}

func testAccCheckSakuraCloudDNSDataSourceNotExists(n string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		_, ok := s.RootModule().Resources[n]
		if ok {
			return fmt.Errorf("Found DNS data source: %s", n)
		}
		return nil
	}
}

func testAccCheckSakuraCloudDNSDataSourceDestroy(s *terraform.State) error {
	client := testAccProvider.Meta().(*api.Client)

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "sakuracloud_dns" {
			continue
		}

		if rs.Primary.ID == "" {
			continue
		}

		_, err := client.DNS.Read(rs.Primary.ID)

		if err == nil {
			return fmt.Errorf("DNS still exists")
		}
	}

	return nil
}

var testAccCheckSakuraCloudDataSourceDNSBase = `
resource "sakuracloud_dns" "foobar" {
    zone = "test-terraform-sakuracloud.com"
    description = "description_test"
    tags = ["tag1","tag2","tag3"]
}`

var testAccCheckSakuraCloudDataSourceDNSConfig = `
resource "sakuracloud_dns" "foobar" {
    zone = "test-terraform-sakuracloud.com"
    description = "description_test"
    tags = ["tag1","tag2","tag3"]
}
data "sakuracloud_dns" "foobar" {
    filter = {
	name = "Zone"
	values = ["name_test"]
    }
}`

var testAccCheckSakuraCloudDataSourceDNSConfig_With_Tag = `
resource "sakuracloud_dns" "foobar" {
    zone = "test-terraform-sakuracloud.com"
    description = "description_test"
    tags = ["tag1","tag2","tag3"]
}
data "sakuracloud_dns" "foobar" {
    filter = {
	name = "Tags"
	values = ["tag1","tag3"]
    }
}`

var testAccCheckSakuraCloudDataSourceDNSConfig_With_NotExists_Tag = `
resource "sakuracloud_dns" "foobar" {
    zone = "test-terraform-sakuracloud.com"
    description = "description_test"
    tags = ["tag1","tag2","tag3"]
}
data "sakuracloud_dns" "foobar" {
    filter = {
	name = "Tags"
	values = ["tag1-xxxxxxx","tag3-xxxxxxxx"]
    }
}`

var testAccCheckSakuraCloudDataSourceDNSConfig_NotExists = `
resource "sakuracloud_dns" "foobar" {
    zone = "test-terraform-sakuracloud.com"
    description = "description_test"
    tags = ["tag1","tag2","tag3"]
}
data "sakuracloud_dns" "foobar" {
    filter = {
	name = "Zone"
	values = ["xxxxxxxxxxxxxxxxxx"]
    }
}`
<commit_msg>Fix DNS test<commit_after>package sakuracloud

import (
	"fmt"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/yamamoto-febc/libsacloud/api"
	"testing"
)

func TestAccSakuraCloudDNSDataSource_Basic(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:                  func() { testAccPreCheck(t) },
		Providers:                 testAccProviders,
		PreventPostDestroyRefresh: true,
		CheckDestroy:              testAccCheckSakuraCloudDNSDataSourceDestroy,

		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckSakuraCloudDataSourceDNSBase,
				Check:  testAccCheckSakuraCloudDNSDataSourceID("sakuracloud_dns.foobar"),
			},
			resource.TestStep{
				Config: testAccCheckSakuraCloudDataSourceDNSConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSakuraCloudDNSDataSourceID("data.sakuracloud_dns.foobar"),
					resource.TestCheckResourceAttr("data.sakuracloud_dns.foobar", "zone", "test-terraform-sakuracloud.com"),
					resource.TestCheckResourceAttr("data.sakuracloud_dns.foobar", "description", "description_test"),
					resource.TestCheckResourceAttr("data.sakuracloud_dns.foobar", "tags.#", "3"),
					resource.TestCheckResourceAttr("data.sakuracloud_dns.foobar", "tags.0", "tag1"),
					resource.TestCheckResourceAttr("data.sakuracloud_dns.foobar", "tags.1", "tag2"),
					resource.TestCheckResourceAttr("data.sakuracloud_dns.foobar", "tags.2", "tag3"),
				),
			},
			resource.TestStep{
				Destroy: true,
				Config:  testAccCheckSakuraCloudDataSourceDNSConfig_With_Tag,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSakuraCloudDNSDataSourceID("data.sakuracloud_dns.foobar"),
				),
			},
			resource.TestStep{
				Destroy: true,
				Config:  testAccCheckSakuraCloudDataSourceDNSConfig_NotExists,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSakuraCloudDNSDataSourceNotExists("data.sakuracloud_dns.foobar"),
				),
			},
			resource.TestStep{
				Destroy: true,
				Config:  testAccCheckSakuraCloudDataSourceDNSConfig_With_NotExists_Tag,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSakuraCloudDNSDataSourceNotExists("data.sakuracloud_dns.foobar"),
				),
			},
		},
	})
}

func testAccCheckSakuraCloudDNSDataSourceID(n string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Can't find DNS data source: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("DNS data source ID not set")
		}
		return nil
	}
}

func testAccCheckSakuraCloudDNSDataSourceNotExists(n string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		_, ok := s.RootModule().Resources[n]
		if ok {
			return fmt.Errorf("Found DNS data source: %s", n)
		}
		return nil
	}
}

func testAccCheckSakuraCloudDNSDataSourceDestroy(s *terraform.State) error {
	client := testAccProvider.Meta().(*api.Client)

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "sakuracloud_dns" {
			continue
		}

		if rs.Primary.ID == "" {
			continue
		}

		_, err := client.DNS.Read(rs.Primary.ID)

		if err == nil {
			return fmt.Errorf("DNS still exists")
		}
	}

	return nil
}

var testAccCheckSakuraCloudDataSourceDNSBase = `
resource "sakuracloud_dns" "foobar" {
    zone = "test-terraform-sakuracloud.com"
    description = "description_test"
    tags = ["tag1","tag2","tag3"]
}`

var testAccCheckSakuraCloudDataSourceDNSConfig = `
resource "sakuracloud_dns" "foobar" {
    zone = "test-terraform-sakuracloud.com"
    description = "description_test"
    tags = ["tag1","tag2","tag3"]
}
data "sakuracloud_dns" "foobar" {
    filter = {
	name = "Zone"
	values = ["test-terraform-sakuracloud.com"]
    }
}`

var testAccCheckSakuraCloudDataSourceDNSConfig_With_Tag = `
resource "sakuracloud_dns" "foobar" {
    zone = "test-terraform-sakuracloud.com"
    description = "description_test"
    tags = ["tag1","tag2","tag3"]
}
data "sakuracloud_dns" "foobar" {
    filter = {
	name = "Tags"
	values = ["tag1","tag3"]
    }
}`

var testAccCheckSakuraCloudDataSourceDNSConfig_With_NotExists_Tag = `
resource "sakuracloud_dns" "foobar" {
    zone = "test-terraform-sakuracloud.com"
    description = "description_test"
    tags = ["tag1","tag2","tag3"]
}
data "sakuracloud_dns" "foobar" {
    filter = {
	name = "Tags"
	values = ["tag1-xxxxxxx","tag3-xxxxxxxx"]
    }
}`

var testAccCheckSakuraCloudDataSourceDNSConfig_NotExists = `
resource "sakuracloud_dns" "foobar" {
    zone = "test-terraform-sakuracloud.com"
    description = "description_test"
    tags = ["tag1","tag2","tag3"]
}
data "sakuracloud_dns" "foobar" {
    filter = {
	name = "Zone"
	values = ["xxxxxxxxxxxxxxxxxx"]
    }
}`
<|endoftext|>


<commit_before>package builds

import (
	"fmt"
	"sync"
	"time"

	"k8s.io/kubernetes/pkg/util/wait"

	g "github.com/onsi/ginkgo"
	o "github.com/onsi/gomega"

	buildapi "github.com/openshift/origin/pkg/build/api"
	exutil "github.com/openshift/origin/test/extended/util"
)

var _ = g.Describe("builds: parallel: oc start-build", func() {
	defer g.GinkgoRecover()
	var (
		buildFixture      = exutil.FixturePath("..", "extended", "fixtures", "test-build.json")
		exampleDockerfile = exutil.FixturePath("..", "extended", "fixtures", "test-build-app", "Dockerfile")
		exampleBuild      = exutil.FixturePath("..", "extended", "fixtures", "test-build-app")
		oc                = exutil.NewCLI("cli-start-build", exutil.KubeConfigPath())
	)

	g.JustBeforeEach(func() {
		g.By("waiting for builder service account")
		err := exutil.WaitForBuilderAccount(oc.KubeREST().ServiceAccounts(oc.Namespace()))
		o.Expect(err).NotTo(o.HaveOccurred())
		oc.Run("create").Args("-f", buildFixture).Execute()
	})

	g.Describe("oc start-build --wait", func() {
		g.It("should start a build and wait for the build to complete", func() {
			g.By("starting the build with --wait flag")
			out, err := oc.Run("start-build").Args("sample-build", "--wait").Output()
			o.Expect(err).NotTo(o.HaveOccurred())

			g.By(fmt.Sprintf("verifying the build %q status", out))
			build, err := oc.REST().Builds(oc.Namespace()).Get(out)
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(build.Status.Phase).Should(o.BeEquivalentTo(buildapi.BuildPhaseComplete))
		})

		g.It("should start a build and wait for the build to fail", func() {
			g.By("starting the build with --wait flag but wrong --commit")
			out, err := oc.Run("start-build").
				Args("sample-build", "--wait", "--commit", "fffffff").
				Output()
			o.Expect(err).To(o.HaveOccurred())
			o.Expect(out).Should(o.ContainSubstring(`status is "Failed"`))
		})
	})

	g.Describe("binary builds", func() {
		g.It("should accept --from-file as input", func() {
			g.By("starting the build with a Dockerfile")
			out, err := oc.Run("start-build").Args("sample-build", "--follow", "--wait", fmt.Sprintf("--from-file=%s", exampleDockerfile)).Output()
			g.By(fmt.Sprintf("verifying the build %q status", out))
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(out).To(o.ContainSubstring("Uploading file"))
			o.Expect(out).To(o.ContainSubstring("as binary input for the build ..."))
			o.Expect(out).To(o.ContainSubstring("Successfully built"))

			build, err := oc.REST().Builds(oc.Namespace()).Get("sample-build-1")
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(build.Status.Phase).Should(o.BeEquivalentTo(buildapi.BuildPhaseComplete))
		})

		g.It("should accept --from-dir as input", func() {
			g.By("starting the build with a directory")
			out, err := oc.Run("start-build").Args("sample-build", "--follow", "--wait", fmt.Sprintf("--from-dir=%s", exampleBuild)).Output()
			g.By(fmt.Sprintf("verifying the build %q status", out))
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(out).To(o.ContainSubstring("Uploading directory"))
			o.Expect(out).To(o.ContainSubstring("as binary input for the build ..."))
			o.Expect(out).To(o.ContainSubstring("Successfully built"))

			build, err := oc.REST().Builds(oc.Namespace()).Get("sample-build-1")
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(build.Status.Phase).Should(o.BeEquivalentTo(buildapi.BuildPhaseComplete))
		})

		g.It("should accept --from-repo as input", func() {
			g.By("starting the build with a Git repository")
			out, err := oc.Run("start-build").Args("sample-build", "--follow", "--wait", fmt.Sprintf("--from-repo=%s", exampleBuild)).Output()
			g.By(fmt.Sprintf("verifying the build %q status", out))
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(out).To(o.ContainSubstring("Uploading Git repository"))
			o.Expect(out).To(o.ContainSubstring("as binary input for the build ..."))
			o.Expect(out).To(o.ContainSubstring("Successfully built"))

			build, err := oc.REST().Builds(oc.Namespace()).Get("sample-build-1")
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(build.Status.Phase).Should(o.BeEquivalentTo(buildapi.BuildPhaseComplete))
		})
	})

	g.Describe("cancelling build started by oc start-build --wait", func() {
		g.It("should start a build and wait for the build to cancel", func() {
			g.By("starting the build with --wait flag")
			var wg sync.WaitGroup
			wg.Add(1)
			go func() {
				defer g.GinkgoRecover()
				out, err := oc.Run("start-build").Args("sample-build", "--wait").Output()
				defer wg.Done()
				o.Expect(err).To(o.HaveOccurred())
				o.Expect(out).Should(o.ContainSubstring(`status is "Cancelled"`))
			}()

			g.By("getting the build name")
			var buildName string
			wait.Poll(time.Duration(100*time.Millisecond), time.Duration(60*time.Second), func() (bool, error) {
				out, err := oc.Run("get").
					Args("build", "--template", "{{ (index .items 0).metadata.name }}").Output()
				// Give it second chance in case the build resource was not created yet
				if err != nil || len(out) == 0 {
					return false, nil
				}
				buildName = out
				return true, nil
			})

			o.Expect(buildName).ToNot(o.BeEmpty())

			g.By(fmt.Sprintf("cancelling the build %q", buildName))
			err := oc.Run("cancel-build").Args(buildName).Execute()
			o.Expect(err).ToNot(o.HaveOccurred())
			wg.Wait()
		})

	})

})
<commit_msg>Fix extended tests for --from-* binary<commit_after>package builds

import (
	"fmt"
	"sync"
	"time"

	"k8s.io/kubernetes/pkg/util/wait"

	g "github.com/onsi/ginkgo"
	o "github.com/onsi/gomega"

	buildapi "github.com/openshift/origin/pkg/build/api"
	exutil "github.com/openshift/origin/test/extended/util"
)

var _ = g.Describe("builds: parallel: oc start-build", func() {
	defer g.GinkgoRecover()
	var (
		buildFixture   = exutil.FixturePath("..", "extended", "fixtures", "test-build.json")
		exampleGemfile = exutil.FixturePath("..", "extended", "fixtures", "test-build-app", "Gemfile")
		exampleBuild   = exutil.FixturePath("..", "extended", "fixtures", "test-build-app")
		oc             = exutil.NewCLI("cli-start-build", exutil.KubeConfigPath())
	)

	g.JustBeforeEach(func() {
		g.By("waiting for builder service account")
		err := exutil.WaitForBuilderAccount(oc.KubeREST().ServiceAccounts(oc.Namespace()))
		o.Expect(err).NotTo(o.HaveOccurred())
		oc.Run("create").Args("-f", buildFixture).Execute()
	})

	g.Describe("oc start-build --wait", func() {
		g.It("should start a build and wait for the build to complete", func() {
			g.By("starting the build with --wait flag")
			out, err := oc.Run("start-build").Args("sample-build", "--wait").Output()
			o.Expect(err).NotTo(o.HaveOccurred())

			g.By(fmt.Sprintf("verifying the build %q status", out))
			build, err := oc.REST().Builds(oc.Namespace()).Get(out)
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(build.Status.Phase).Should(o.BeEquivalentTo(buildapi.BuildPhaseComplete))
		})

		g.It("should start a build and wait for the build to fail", func() {
			g.By("starting the build with --wait flag but wrong --commit")
			out, err := oc.Run("start-build").
				Args("sample-build", "--wait", "--commit", "fffffff").
				Output()
			o.Expect(err).To(o.HaveOccurred())
			o.Expect(out).Should(o.ContainSubstring(`status is "Failed"`))
		})
	})

	g.Describe("binary builds", func() {
		g.It("should accept --from-file as input", func() {
			g.By("starting the build with a Dockerfile")
			out, err := oc.Run("start-build").Args("sample-build", "--follow", "--wait", fmt.Sprintf("--from-file=%s", exampleGemfile)).Output()
			g.By(fmt.Sprintf("verifying the build %q status", out))
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(out).To(o.ContainSubstring("Uploading file"))
			o.Expect(out).To(o.ContainSubstring("as binary input for the build ..."))
			o.Expect(out).To(o.ContainSubstring("Your bundle is complete"))

			build, err := oc.REST().Builds(oc.Namespace()).Get("sample-build-1")
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(build.Status.Phase).Should(o.BeEquivalentTo(buildapi.BuildPhaseComplete))
		})

		g.It("should accept --from-dir as input", func() {
			g.By("starting the build with a directory")
			out, err := oc.Run("start-build").Args("sample-build", "--follow", "--wait", fmt.Sprintf("--from-dir=%s", exampleBuild)).Output()
			g.By(fmt.Sprintf("verifying the build %q status", out))
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(out).To(o.ContainSubstring("Uploading directory"))
			o.Expect(out).To(o.ContainSubstring("as binary input for the build ..."))
			o.Expect(out).To(o.ContainSubstring("Your bundle is complete"))

			build, err := oc.REST().Builds(oc.Namespace()).Get("sample-build-1")
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(build.Status.Phase).Should(o.BeEquivalentTo(buildapi.BuildPhaseComplete))
		})

		g.It("should accept --from-repo as input", func() {
			g.By("starting the build with a Git repository")
			out, err := oc.Run("start-build").Args("sample-build", "--follow", "--wait", fmt.Sprintf("--from-repo=%s", exampleBuild)).Output()
			g.By(fmt.Sprintf("verifying the build %q status", out))
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(out).To(o.ContainSubstring("Uploading Git repository"))
			o.Expect(out).To(o.ContainSubstring("as binary input for the build ..."))
			o.Expect(out).To(o.ContainSubstring("Your bundle is complete"))

			build, err := oc.REST().Builds(oc.Namespace()).Get("sample-build-1")
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(build.Status.Phase).Should(o.BeEquivalentTo(buildapi.BuildPhaseComplete))
		})
	})

	g.Describe("cancelling build started by oc start-build --wait", func() {
		g.It("should start a build and wait for the build to cancel", func() {
			g.By("starting the build with --wait flag")
			var wg sync.WaitGroup
			wg.Add(1)
			go func() {
				defer g.GinkgoRecover()
				out, err := oc.Run("start-build").Args("sample-build", "--wait").Output()
				defer wg.Done()
				o.Expect(err).To(o.HaveOccurred())
				o.Expect(out).Should(o.ContainSubstring(`status is "Cancelled"`))
			}()

			g.By("getting the build name")
			var buildName string
			wait.Poll(time.Duration(100*time.Millisecond), time.Duration(60*time.Second), func() (bool, error) {
				out, err := oc.Run("get").
					Args("build", "--template", "{{ (index .items 0).metadata.name }}").Output()
				// Give it second chance in case the build resource was not created yet
				if err != nil || len(out) == 0 {
					return false, nil
				}
				buildName = out
				return true, nil
			})

			o.Expect(buildName).ToNot(o.BeEmpty())

			g.By(fmt.Sprintf("cancelling the build %q", buildName))
			err := oc.Run("cancel-build").Args(buildName).Execute()
			o.Expect(err).ToNot(o.HaveOccurred())
			wg.Wait()
		})

	})

})
<|endoftext|>