add(cepgo): import github.com/cloudsigma/cepgo
This commit is contained in:
186
third_party/github.com/cloudsigma/cepgo/cepgo.go
vendored
Normal file
186
third_party/github.com/cloudsigma/cepgo/cepgo.go
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
// Cepko implements easy-to-use communication with CloudSigma's VMs through a
|
||||
// virtual serial port without bothering with formatting the messages properly
|
||||
// nor parsing the output with the specific and sometimes confusing shell tools
|
||||
// for that purpose.
|
||||
//
|
||||
// Having the server definition accessible by the VM can be useful in various
|
||||
// ways. For example it is possible to easily determine from within the VM,
|
||||
// which network interfaces are connected to public and which to private
|
||||
// network. Another use is to pass some data to initial VM setup scripts, like
|
||||
// setting the hostname to the VM name or passing ssh public keys through
|
||||
// server meta.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// package main
|
||||
//
|
||||
// import (
|
||||
// "fmt"
|
||||
//
|
||||
// "github.com/cloudsigma/cepgo"
|
||||
// )
|
||||
//
|
||||
// func main() {
|
||||
// c := cepgo.NewCepgo()
|
||||
// result, err := c.Meta()
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// fmt.Printf("%#v", result)
|
||||
// }
|
||||
//
|
||||
// Output:
|
||||
//
|
||||
// map[string]string{
|
||||
// "optimize_for":"custom",
|
||||
// "ssh_public_key":"ssh-rsa AAA...",
|
||||
// "description":"[...]",
|
||||
// }
|
||||
//
|
||||
// For more information take a look at the Server Context section API Docs:
|
||||
// http://cloudsigma-docs.readthedocs.org/en/latest/server_context.html
|
||||
package cepgo
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/tarm/goserial"
|
||||
)
|
||||
|
||||
const (
|
||||
requestPattern = "<\n%s\n>"
|
||||
EOT = '\x04' // End Of Transmission
|
||||
)
|
||||
|
||||
var (
|
||||
SerialPort string = "/dev/ttyS1"
|
||||
Baud int = 115200
|
||||
)
|
||||
|
||||
// Sets the serial port. If the operating system is windows CloudSigma's server
|
||||
// context is at COM2 port, otherwise (linux, freebsd, darwin) the port is
|
||||
// being left to the default /dev/ttyS1.
|
||||
func init() {
|
||||
if runtime.GOOS == "windows" {
|
||||
SerialPort = "COM2"
|
||||
}
|
||||
}
|
||||
|
||||
// The default fetcher makes the connection to the serial port,
|
||||
// writes given query and reads until the EOT symbol.
|
||||
func fetchViaSerialPort(key string) ([]byte, error) {
|
||||
config := &serial.Config{Name: SerialPort, Baud: Baud}
|
||||
connection, err := serial.OpenPort(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(requestPattern, key)
|
||||
if _, err := connection.Write([]byte(query)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(connection)
|
||||
answer, err := reader.ReadBytes(EOT)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return answer[0 : len(answer)-1], nil
|
||||
}
|
||||
|
||||
// Queries to the serial port can be executed only from instance of this type.
|
||||
// The result from each of them can be either interface{}, map[string]string or
|
||||
// a single in case of single value is returned. There is also a public metod
|
||||
// who directly calls the fetcher and returns raw []byte from the serial port.
|
||||
type Cepgo struct {
|
||||
fetcher func(string) ([]byte, error)
|
||||
}
|
||||
|
||||
// Creates a Cepgo instance with the default serial port fetcher.
|
||||
func NewCepgo() *Cepgo {
|
||||
cepgo := new(Cepgo)
|
||||
cepgo.fetcher = fetchViaSerialPort
|
||||
return cepgo
|
||||
}
|
||||
|
||||
// Creates a Cepgo instance with custom fetcher.
|
||||
func NewCepgoFetcher(fetcher func(string) ([]byte, error)) *Cepgo {
|
||||
cepgo := new(Cepgo)
|
||||
cepgo.fetcher = fetcher
|
||||
return cepgo
|
||||
}
|
||||
|
||||
// Fetches raw []byte from the serial port using directly the fetcher member.
|
||||
func (c *Cepgo) FetchRaw(key string) ([]byte, error) {
|
||||
return c.fetcher(key)
|
||||
}
|
||||
|
||||
// Fetches a single key and tries to unmarshal the result to json and returns
|
||||
// it. If the unmarshalling fails it's safe to assume the result it's just a
|
||||
// string and returns it.
|
||||
func (c *Cepgo) Key(key string) (interface{}, error) {
|
||||
var result interface{}
|
||||
|
||||
fetched, err := c.FetchRaw(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(fetched, &result)
|
||||
if err != nil {
|
||||
return string(fetched), nil
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Fetches all the server context. Equivalent of c.Key("")
|
||||
func (c *Cepgo) All() (interface{}, error) {
|
||||
return c.Key("")
|
||||
}
|
||||
|
||||
// Fetches only the object meta field and makes sure to return a proper
|
||||
// map[string]string
|
||||
func (c *Cepgo) Meta() (map[string]string, error) {
|
||||
rawMeta, err := c.Key("/meta/")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return typeAssertToMapOfStrings(rawMeta)
|
||||
}
|
||||
|
||||
// Fetches only the global context and makes sure to return a proper
|
||||
// map[string]string
|
||||
func (c *Cepgo) GlobalContext() (map[string]string, error) {
|
||||
rawContext, err := c.Key("/global_context/")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return typeAssertToMapOfStrings(rawContext)
|
||||
}
|
||||
|
||||
// Just a little helper function that uses type assertions in order to convert
|
||||
// a interface{} to map[string]string if this is possible.
|
||||
func typeAssertToMapOfStrings(raw interface{}) (map[string]string, error) {
|
||||
result := make(map[string]string)
|
||||
|
||||
dictionary, ok := raw.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, errors.New("Received bytes are formatted badly")
|
||||
}
|
||||
|
||||
for key, rawValue := range dictionary {
|
||||
if value, ok := rawValue.(string); ok {
|
||||
result[key] = value
|
||||
} else {
|
||||
return nil, errors.New("Server context metadata is formatted badly")
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
Reference in New Issue
Block a user