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

package cors

import (
	"net/textproto"
	"strconv"
	"strings"

	"github.com/google/go-safeweb/safehttp"
)

const requiredHeader string = "X-Cors"

var disallowedContentTypes = map[string]bool{
	"application/x-www-form-urlencoded": true,
	"multipart/form-data":               true,
	"text/plain":                        true,
}

// Interceptor handles CORS requests based on its settings.
//
// For more info about CORS, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
//
// Constraints
//
// The content types "application/x-www-form-urlencoded", "multipart/form-data"
// and "text/plain" are banned and will result in a  415 Unsupported Media Type
// response.
//
// Each CORS request must contain the header "X-Cors: 1".
//
// All of this is to prevent XSRF.
type Interceptor struct {
	// AllowedOrigins determines which origins should be allowed in the
	// Access-Control-Allow-Origin header.
	AllowedOrigins map[string]bool
	allowedHeaders map[string]bool
	// ExposedHeaders determines which headers should be set in the
	// Access-Control-Expose-Headers header. This controls which headers are
	//  accessible by JavaScript in the response.
	//
	// If ExposedHeaders is nil, then the header is not set, meaning that nothing
	// is exposed.
	ExposedHeaders []string
	// AllowCredentials determines if Access-Control-Allow-Credentials should be
	// set to true, which would allow cookies to be attached to requests.
	AllowCredentials bool
	// MaxAge sets the Access-Control-Max-Age header, indicating how many seconds
	// the results of a preflight request can be cached.
	//
	// MaxAge=0 results in MaxAge: 5, the default used by Chromium according to
	// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
	MaxAge int
}

// Default creates a CORS Interceptor with default settings.
// Those defaults are:
//  - No Exposed Headers
//  - No Allowed Headers
//  - AllowCredentials: false
//  - MaxAge: 5 seconds
func Default(allowedOrigins ...string) *Interceptor {
	ao := map[string]bool{}
	for _, o := range allowedOrigins {
		ao[o] = true
	}
	return &Interceptor{
		AllowedOrigins: ao,
		allowedHeaders: map[string]bool{},
	}
}

// SetAllowedHeaders sets the headers allowed in the Access-Control-Allow-Headers
// header. The headers are first canonicalized using textproto.CanonicalMIMEHeaderKey.
// The wildcard "*" is not allowed.
func (it *Interceptor) SetAllowedHeaders(headers ...string) {
	it.allowedHeaders = map[string]bool{}
	for _, h := range headers {
		if h == "*" {
			continue
		}
		it.allowedHeaders[textproto.CanonicalMIMEHeaderKey(h)] = true
	}
}

// Before handles the IncomingRequest according to the settings specified in the
// Interceptor and sets the appropriate subset of the following headers:
//
//  - Access-Control-Allow-Credentials
//  - Access-Control-Allow-Headers
//  - Access-Control-Allow-Methods
//  - Access-Control-Allow-Origin
//  - Access-Control-Expose-Headers
//  - Access-Control-Max-Age
//  - Vary
func (it *Interceptor) Before(w *safehttp.ResponseWriter, r *safehttp.IncomingRequest) safehttp.Result {
	origin := r.Header.Get("Origin")
	if origin != "" && !it.AllowedOrigins[origin] {
		return w.WriteError(safehttp.StatusForbidden)
	}
	h := w.Header()
	allowOrigin := h.Claim("Access-Control-Allow-Origin")
	if h.IsClaimed("Vary") {
		return w.WriteError(safehttp.StatusInternalServerError)
	}

	allowCredentials := h.Claim("Access-Control-Allow-Credentials")

	var status safehttp.StatusCode
	m := r.Method()
	if m == safehttp.MethodOptions {
		status = it.preflight(w, r)
	} else if m == safehttp.MethodHead {
		status = safehttp.StatusMethodNotAllowed
	} else {
		status = it.request(w, r)
	}

	if status != 0 && status != safehttp.StatusNoContent {
		return w.WriteError(status)
	}

	if origin != "" {
		allowOrigin([]string{origin})
		appendToVary(w, "Origin")
	}
	if r.Header.Get("Cookie") != "" && it.AllowCredentials {
		// TODO: handle other credentials than cookies:
		// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
		allowCredentials([]string{"true"})
	}

	if status == safehttp.StatusNoContent {
		return w.NoContent()
	}
	return safehttp.Result{}
}

func appendToVary(w *safehttp.ResponseWriter, val string) {
	h := w.Header()
	if curr := h.Get("Vary"); curr != "" {
		h.Set("Vary", curr+", "+val)
	} else {
		h.Set("Vary", val)
	}
}

// preflight handles requests that have the method OPTIONS.
func (it *Interceptor) preflight(w *safehttp.ResponseWriter, r *safehttp.IncomingRequest) safehttp.StatusCode {
	rh := r.Header
	method := rh.Get("Access-Control-Request-Method")
	if method == "" || method == safehttp.MethodHead {
		return safehttp.StatusForbidden
	}

	headers := rh.Get("Access-Control-Request-Headers")
	if headers != "" {
		for _, h := range strings.Split(headers, ", ") {
			h = textproto.CanonicalMIMEHeaderKey(h)
			if !it.allowedHeaders[h] && h != requiredHeader {
				return safehttp.StatusForbidden
			}
		}
	}

	wh := w.Header()
	allowMethods := wh.Claim("Access-Control-Allow-Methods")
	allowHeaders := wh.Claim("Access-Control-Allow-Headers")
	maxAge := wh.Claim("Access-Control-Max-Age")

	allowMethods([]string{method})
	if headers != "" {
		allowHeaders([]string{headers})
	}
	n := it.MaxAge
	if n == 0 {
		n = 5
	}
	maxAge([]string{strconv.Itoa(n)})
	return safehttp.StatusNoContent
}

// request handles all requests that are not preflight requests.
func (it *Interceptor) request(w *safehttp.ResponseWriter, r *safehttp.IncomingRequest) safehttp.StatusCode {
	h := r.Header
	if h.Get(requiredHeader) != "1" {
		return safehttp.StatusPreconditionFailed
	}

	if ct := h.Get("Content-Type"); ct == "" || disallowedContentTypes[ct] {
		return safehttp.StatusUnsupportedMediaType
	}

	if exposeHeaders := w.Header().Claim("Access-Control-Expose-Headers"); it.ExposedHeaders != nil {
		exposeHeaders([]string{strings.Join(it.ExposedHeaders, ", ")})
	}
	return 0
}
<commit_msg>Refactored big if-else chain into switch statement<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cors

import (
	"net/textproto"
	"strconv"
	"strings"

	"github.com/google/go-safeweb/safehttp"
)

const requiredHeader string = "X-Cors"

var disallowedContentTypes = map[string]bool{
	"application/x-www-form-urlencoded": true,
	"multipart/form-data":               true,
	"text/plain":                        true,
}

// Interceptor handles CORS requests based on its settings.
//
// For more info about CORS, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
//
// Constraints
//
// The content types "application/x-www-form-urlencoded", "multipart/form-data"
// and "text/plain" are banned and will result in a  415 Unsupported Media Type
// response.
//
// Each CORS request must contain the header "X-Cors: 1".
//
// All of this is to prevent XSRF.
type Interceptor struct {
	// AllowedOrigins determines which origins should be allowed in the
	// Access-Control-Allow-Origin header.
	AllowedOrigins map[string]bool
	allowedHeaders map[string]bool
	// ExposedHeaders determines which headers should be set in the
	// Access-Control-Expose-Headers header. This controls which headers are
	//  accessible by JavaScript in the response.
	//
	// If ExposedHeaders is nil, then the header is not set, meaning that nothing
	// is exposed.
	ExposedHeaders []string
	// AllowCredentials determines if Access-Control-Allow-Credentials should be
	// set to true, which would allow cookies to be attached to requests.
	AllowCredentials bool
	// MaxAge sets the Access-Control-Max-Age header, indicating how many seconds
	// the results of a preflight request can be cached.
	//
	// MaxAge=0 results in MaxAge: 5, the default used by Chromium according to
	// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
	MaxAge int
}

// Default creates a CORS Interceptor with default settings.
// Those defaults are:
//  - No Exposed Headers
//  - No Allowed Headers
//  - AllowCredentials: false
//  - MaxAge: 5 seconds
func Default(allowedOrigins ...string) *Interceptor {
	ao := map[string]bool{}
	for _, o := range allowedOrigins {
		ao[o] = true
	}
	return &Interceptor{
		AllowedOrigins: ao,
		allowedHeaders: map[string]bool{},
	}
}

// SetAllowedHeaders sets the headers allowed in the Access-Control-Allow-Headers
// header. The headers are first canonicalized using textproto.CanonicalMIMEHeaderKey.
// The wildcard "*" is not allowed.
func (it *Interceptor) SetAllowedHeaders(headers ...string) {
	it.allowedHeaders = map[string]bool{}
	for _, h := range headers {
		if h == "*" {
			continue
		}
		it.allowedHeaders[textproto.CanonicalMIMEHeaderKey(h)] = true
	}
}

// Before handles the IncomingRequest according to the settings specified in the
// Interceptor and sets the appropriate subset of the following headers:
//
//  - Access-Control-Allow-Credentials
//  - Access-Control-Allow-Headers
//  - Access-Control-Allow-Methods
//  - Access-Control-Allow-Origin
//  - Access-Control-Expose-Headers
//  - Access-Control-Max-Age
//  - Vary
func (it *Interceptor) Before(w *safehttp.ResponseWriter, r *safehttp.IncomingRequest) safehttp.Result {
	origin := r.Header.Get("Origin")
	if origin != "" && !it.AllowedOrigins[origin] {
		return w.WriteError(safehttp.StatusForbidden)
	}
	h := w.Header()
	allowOrigin := h.Claim("Access-Control-Allow-Origin")
	if h.IsClaimed("Vary") {
		return w.WriteError(safehttp.StatusInternalServerError)
	}

	allowCredentials := h.Claim("Access-Control-Allow-Credentials")

	var status safehttp.StatusCode
	switch r.Method() {
	case safehttp.MethodOptions:
		status = it.preflight(w, r)
	case safehttp.MethodHead:
		status = safehttp.StatusMethodNotAllowed
	default:
		status = it.request(w, r)
	}

	if status != 0 && status != safehttp.StatusNoContent {
		return w.WriteError(status)
	}

	if origin != "" {
		allowOrigin([]string{origin})
		appendToVary(w, "Origin")
	}
	if r.Header.Get("Cookie") != "" && it.AllowCredentials {
		// TODO: handle other credentials than cookies:
		// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
		allowCredentials([]string{"true"})
	}

	if status == safehttp.StatusNoContent {
		return w.NoContent()
	}
	return safehttp.Result{}
}

func appendToVary(w *safehttp.ResponseWriter, val string) {
	h := w.Header()
	if curr := h.Get("Vary"); curr != "" {
		h.Set("Vary", curr+", "+val)
	} else {
		h.Set("Vary", val)
	}
}

// preflight handles requests that have the method OPTIONS.
func (it *Interceptor) preflight(w *safehttp.ResponseWriter, r *safehttp.IncomingRequest) safehttp.StatusCode {
	rh := r.Header
	method := rh.Get("Access-Control-Request-Method")
	if method == "" || method == safehttp.MethodHead {
		return safehttp.StatusForbidden
	}

	headers := rh.Get("Access-Control-Request-Headers")
	if headers != "" {
		for _, h := range strings.Split(headers, ", ") {
			h = textproto.CanonicalMIMEHeaderKey(h)
			if !it.allowedHeaders[h] && h != requiredHeader {
				return safehttp.StatusForbidden
			}
		}
	}

	wh := w.Header()
	allowMethods := wh.Claim("Access-Control-Allow-Methods")
	allowHeaders := wh.Claim("Access-Control-Allow-Headers")
	maxAge := wh.Claim("Access-Control-Max-Age")

	allowMethods([]string{method})
	if headers != "" {
		allowHeaders([]string{headers})
	}
	n := it.MaxAge
	if n == 0 {
		n = 5
	}
	maxAge([]string{strconv.Itoa(n)})
	return safehttp.StatusNoContent
}

// request handles all requests that are not preflight requests.
func (it *Interceptor) request(w *safehttp.ResponseWriter, r *safehttp.IncomingRequest) safehttp.StatusCode {
	h := r.Header
	if h.Get(requiredHeader) != "1" {
		return safehttp.StatusPreconditionFailed
	}

	if ct := h.Get("Content-Type"); ct == "" || disallowedContentTypes[ct] {
		return safehttp.StatusUnsupportedMediaType
	}

	if exposeHeaders := w.Header().Claim("Access-Control-Expose-Headers"); it.ExposedHeaders != nil {
		exposeHeaders([]string{strings.Join(it.ExposedHeaders, ", ")})
	}
	return 0
}
<|endoftext|>


<commit_before>/*
	Wrapper for SSH in Go
	Copyright Steven Richards 2015 - <sbrichards@mit.edu>
*/

package easyssh

import (
	"bytes"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"github.com/howeyc/gopass"
	"golang.org/x/crypto/ssh"
	"io/ioutil"
)

type Config struct {
	User     string
	Password string
	KeyPath  string
	Host     string
	Port     string
	Client   *ssh.Client
}

func getKeyFile(keyPath string) (ssh.Signer, error) {
	buf, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return nil, err
	}
	p, rest := pem.Decode(buf)
	if len(rest) > 0 {
		return nil, fmt.Errorf("Failed to decode key")
	}
	pBlock := pem.Block{
		Bytes:   buf,
		Type:    p.Type,
		Headers: p.Headers,
	}
	if x509.IsEncryptedPEMBlock(&pBlock) {
		fmt.Println("Detected a password protected key file")
		decodedKeyBytes, err := tryDecrypt(p, 0)
		if err != nil {
			return nil, err
		}
		// Encode decrypted bytes into decoded PEM structure as if it were in a file
		pBlock = pem.Block{
			Bytes:   decodedKeyBytes,
			Type:    p.Type,
			Headers: p.Headers,
		}
		// Extract SSH key from decrypted PEM in-memory file
		rawkey, err := ssh.ParsePrivateKey(pem.EncodeToMemory(&pBlock))
		if err != nil {
			return nil, err
		}
		return rawkey.(ssh.Signer), nil
	}
	// Non-encrypted key
	key, err := ssh.ParsePrivateKey(buf)
	if err != nil {
		return nil, err
	}
	return key, nil
}

func tryDecrypt(p *pem.Block, count int) ([]byte, error) {
	if count >= 3 {
		return nil, fmt.Errorf("Too many tries")
	} else if count >= 1 {
		fmt.Println("Wrong password, try again")
	}
	fmt.Println("Enter the key's password: ")
	password := gopass.GetPasswd()
	// Decrypt using user's key
	decodedKeyBytes, err := x509.DecryptPEMBlock(p, password)
	if err != nil {
		return tryDecrypt(p, count+1)
	}
	return decodedKeyBytes, nil
}

// Connect takes no arguments and attempts to open an SSH connection.
// It uses the easyssh Config and the parameters it contains.
func (e *Config) Connect() error {
	var sshConfig = &ssh.ClientConfig{}
	var err error
	if e.KeyPath != "" {
		keyFile, err := getKeyFile(e.KeyPath)
		if err != nil {
			return fmt.Errorf("Unable to use specified key file")
		}
		sshConfig = &ssh.ClientConfig{
			User: e.User,
			Auth: []ssh.AuthMethod{
				ssh.PublicKeys(keyFile),
			},
		}
	} else if e.Password != "" {
		sshConfig = &ssh.ClientConfig{
			User: e.User,
			Auth: []ssh.AuthMethod{
				ssh.Password(e.Password),
			},
		}
	}
	e.Client, err = ssh.Dial("tcp", e.Host+":"+e.Port, sshConfig)
	return err
}

// Command executes a single string command.
// To do so it opens a new SSH session, executes the command, and returns stdout as a string.
// If it fails for any reasion it returns an empty string and an error.
func (e *Config) Command(command string) (string, error) {
	session, err := e.Client.NewSession()
	if err != nil {
		return "", fmt.Errorf("Failed to create session: %s\n" + err.Error())
	}
	var stdout bytes.Buffer
	session.Stdout = &stdout
	err = session.Run(command)
	if err != nil {
		return "", fmt.Errorf("Failed to execute command: %s\n" + err.Error())
	}
	return stdout.String(), nil
}

// BatchCommands takes a string slice of commands and a string delimiter.
// The delimiter is appended to the result of each command, it can be an empty string as well.
// It returns whether there were any errors or not and outputs if there are any errors as it runs.
func (e *Config) BatchCommands(commands []string, delimiter string) ([]string, error) {
	results := make([]string, len(commands))
	errors := false
	for _, command := range commands {
		session, err := e.Client.NewSession()
		if err != nil {
			fmt.Printf("Failed to create session: %s\n" + err.Error())
			return nil, err
		}
		var stdout bytes.Buffer
		session.Stdout = &stdout
		err = session.Run(command)
		if err != nil {
			fmt.Printf("Failed to execute %s : %s\n", command, err.Error())
			errors = true
			continue
		}
		output := strings.TrimSpace(stdout.String())
		results = append(results, output)+delimiter)
	}
	if errors {
		return results, fmt.Errorf("There were some errors while executing the commands")
	}
	return results, nil
}
<commit_msg>fix newline<commit_after>/*
	Wrapper for SSH in Go
	Copyright Steven Richards 2015 - <sbrichards@mit.edu>
*/

package easyssh

import (
	"bytes"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"github.com/howeyc/gopass"
	"golang.org/x/crypto/ssh"
	"io/ioutil"
)

type Config struct {
	User     string
	Password string
	KeyPath  string
	Host     string
	Port     string
	Client   *ssh.Client
}

func getKeyFile(keyPath string) (ssh.Signer, error) {
	buf, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return nil, err
	}
	p, rest := pem.Decode(buf)
	if len(rest) > 0 {
		return nil, fmt.Errorf("Failed to decode key")
	}
	pBlock := pem.Block{
		Bytes:   buf,
		Type:    p.Type,
		Headers: p.Headers,
	}
	if x509.IsEncryptedPEMBlock(&pBlock) {
		fmt.Println("Detected a password protected key file")
		decodedKeyBytes, err := tryDecrypt(p, 0)
		if err != nil {
			return nil, err
		}
		// Encode decrypted bytes into decoded PEM structure as if it were in a file
		pBlock = pem.Block{
			Bytes:   decodedKeyBytes,
			Type:    p.Type,
			Headers: p.Headers,
		}
		// Extract SSH key from decrypted PEM in-memory file
		rawkey, err := ssh.ParsePrivateKey(pem.EncodeToMemory(&pBlock))
		if err != nil {
			return nil, err
		}
		return rawkey.(ssh.Signer), nil
	}
	// Non-encrypted key
	key, err := ssh.ParsePrivateKey(buf)
	if err != nil {
		return nil, err
	}
	return key, nil
}

func tryDecrypt(p *pem.Block, count int) ([]byte, error) {
	if count >= 3 {
		return nil, fmt.Errorf("Too many tries")
	} else if count >= 1 {
		fmt.Println("Wrong password, try again")
	}
	fmt.Println("Enter the key's password: ")
	password := gopass.GetPasswd()
	// Decrypt using user's key
	decodedKeyBytes, err := x509.DecryptPEMBlock(p, password)
	if err != nil {
		return tryDecrypt(p, count+1)
	}
	return decodedKeyBytes, nil
}

// Connect takes no arguments and attempts to open an SSH connection.
// It uses the easyssh Config and the parameters it contains.
func (e *Config) Connect() error {
	var sshConfig = &ssh.ClientConfig{}
	var err error
	if e.KeyPath != "" {
		keyFile, err := getKeyFile(e.KeyPath)
		if err != nil {
			return fmt.Errorf("Unable to use specified key file")
		}
		sshConfig = &ssh.ClientConfig{
			User: e.User,
			Auth: []ssh.AuthMethod{
				ssh.PublicKeys(keyFile),
			},
		}
	} else if e.Password != "" {
		sshConfig = &ssh.ClientConfig{
			User: e.User,
			Auth: []ssh.AuthMethod{
				ssh.Password(e.Password),
			},
		}
	}
	e.Client, err = ssh.Dial("tcp", e.Host+":"+e.Port, sshConfig)
	return err
}

// Command executes a single string command.
// To do so it opens a new SSH session, executes the command, and returns stdout as a string.
// If it fails for any reasion it returns an empty string and an error.
func (e *Config) Command(command string) (string, error) {
	session, err := e.Client.NewSession()
	if err != nil {
		return "", fmt.Errorf("Failed to create session: %s\n" + err.Error())
	}
	var stdout bytes.Buffer
	session.Stdout = &stdout
	err = session.Run(command)
	if err != nil {
		return "", fmt.Errorf("Failed to execute command: %s\n" + err.Error())
	}
	return stdout.String(), nil
}

// BatchCommands takes a string slice of commands and a string delimiter.
// The delimiter is appended to the result of each command, it can be an empty string as well.
// It returns whether there were any errors or not and outputs if there are any errors as it runs.
func (e *Config) BatchCommands(commands []string, delimiter string) ([]string, error) {
	results := make([]string, len(commands))
	errors := false
	for _, command := range commands {
		session, err := e.Client.NewSession()
		if err != nil {
			fmt.Printf("Failed to create session: %s\n" + err.Error())
			return nil, err
		}
		var stdout bytes.Buffer
		session.Stdout = &stdout
		err = session.Run(command)
		if err != nil {
			fmt.Printf("Failed to execute %s : %s\n", command, err.Error())
			errors = true
			continue
		}
		output := strings.TrimSpace(stdout.String())
		results = append(results, output+delimiter)
	}
	if errors {
		return results, fmt.Errorf("There were some errors while executing the commands")
	}
	return results, nil
}
<|endoftext|>


<commit_before>package tests
import (
    "testing"
    "github.com/zubairhamed/go-lwm2m"
    "github.com/zubairhamed/go-lwm2m/objects/oma"
    "github.com/zubairhamed/go-lwm2m/examples/obj/basic"
    "github.com/zubairhamed/go-lwm2m/registry"
    "github.com/stretchr/testify/assert"
    "time"
)

func TestExampleObjects(t *testing.T) {
    client := lwm2m.NewLWM2MClient(":0", "localhost:5683")

    reg := registry.NewDefaultObjectRegistry()

    client.EnableObject(oma.OBJECT_LWM2M_DEVICE, basic.NewExampleDeviceObject(reg))
    client.EnableObject(oma.OBJECT_LWM2M_SECURITY, basic.NewExampleSecurityObject(reg))
    client.EnableObject(oma.OBJECT_LWM2M_ACCESS_CONTROL, basic.NewExampleAccessControlObject(reg))
    client.EnableObject(oma.OBJECT_LWM2M_CONNECTIVITY_MONITORING, basic.NewExampleConnectivityMonitoringObject(reg))
    client.EnableObject(oma.OBJECT_LWM2M_CONNECTIVITY_STATISTICS, basic.NewExampleConnectivityStatisticsObject(reg))
    client.EnableObject(oma.OBJECT_LWM2M_FIRMWARE_UPDATE, basic.NewExampleFirmwareUpdateObject(reg))
    client.EnableObject(oma.OBJECT_LWM2M_LOCATION, basic.NewExampleLocationObject(reg))
    client.EnableObject(oma.OBJECT_LWM2M_SERVER, basic.NewExampleConnectivityMonitoringObject(reg))

    instDevice := reg.CreateObjectInstance(oma.OBJECT_LWM2M_DEVICE, 0)
    instSec := reg.CreateObjectInstance(oma.OBJECT_LWM2M_SECURITY, 0)
    instAccCtrl := reg.CreateObjectInstance(oma.OBJECT_LWM2M_ACCESS_CONTROL, 0)
    instConnMon := reg.CreateObjectInstance(oma.OBJECT_LWM2M_CONNECTIVITY_MONITORING, 0)
    instConnStats := reg.CreateObjectInstance(oma.OBJECT_LWM2M_CONNECTIVITY_STATISTICS, 0)
    instFwUpdate := reg.CreateObjectInstance(oma.OBJECT_LWM2M_FIRMWARE_UPDATE, 0)
    instLocation := reg.CreateObjectInstance(oma.OBJECT_LWM2M_LOCATION, 0)
    instServer := reg.CreateObjectInstance(oma.OBJECT_LWM2M_SERVER, 0)

    client.AddObjectInstances(
        instDevice,
        instSec,
        instAccCtrl,
        instConnMon,
        instConnStats,
        instFwUpdate,
        instLocation,
        instServer,
    )

    en := client.GetObjectEnabler(oma.OBJECT_LWM2M_DEVICE)
    en.OnRead(0, 0)
    // Device Object
    tests := []struct {
        instanceId  int
        resourceId  int
        expected    interface{}
    }{
        {0, 0, "Open Mobile Alliance"},
        {0, 1, "Lightweight M2M Client"},
        {0, 2, "345000123"},
        {0, 3, "1.0"},
        // {0, 6, []int{1, 5}},
        // {0, 7, []int{3800, 5000}},
        // {0, 8, []int{125, 900}},
        {0, 10, 15},
        // {0, 11, []int{0}},
        {0, 13, time.Unix(1367491215, 0)},
        {0, 14, "+02:00"},
        {0, 16, "U"},
    }

    for _, c := range tests {
        ret, _ := en.OnRead(c.instanceId, c.resourceId)
        val := ret.GetValue()

        assert.Equal(t, val, c.expected, "Unexpected value returned for enabler OnRead: ", val, "vs", c.expected)
    }

}<commit_msg>OMA Objects test updates<commit_after>package tests
import (
    "testing"
    "github.com/zubairhamed/go-lwm2m"
    "github.com/zubairhamed/go-lwm2m/objects/oma"
    "github.com/zubairhamed/go-lwm2m/examples/obj/basic"
    "github.com/zubairhamed/go-lwm2m/registry"
    "github.com/stretchr/testify/assert"
    "time"
    "github.com/zubairhamed/go-lwm2m/api"
)

func TestExampleObjects(t *testing.T) {
    client := lwm2m.NewLWM2MClient(":0", "localhost:5683")

    reg := registry.NewDefaultObjectRegistry()

    client.EnableObject(oma.OBJECT_LWM2M_DEVICE, basic.NewExampleDeviceObject(reg))
    client.EnableObject(oma.OBJECT_LWM2M_SECURITY, basic.NewExampleSecurityObject(reg))
    client.EnableObject(oma.OBJECT_LWM2M_ACCESS_CONTROL, basic.NewExampleAccessControlObject(reg))
    client.EnableObject(oma.OBJECT_LWM2M_CONNECTIVITY_MONITORING, basic.NewExampleConnectivityMonitoringObject(reg))
    client.EnableObject(oma.OBJECT_LWM2M_CONNECTIVITY_STATISTICS, basic.NewExampleConnectivityStatisticsObject(reg))
    client.EnableObject(oma.OBJECT_LWM2M_FIRMWARE_UPDATE, basic.NewExampleFirmwareUpdateObject(reg))
    client.EnableObject(oma.OBJECT_LWM2M_LOCATION, basic.NewExampleLocationObject(reg))
    client.EnableObject(oma.OBJECT_LWM2M_SERVER, basic.NewExampleConnectivityMonitoringObject(reg))

    instDevice := reg.CreateObjectInstance(oma.OBJECT_LWM2M_DEVICE, 0)
    instSec := reg.CreateObjectInstance(oma.OBJECT_LWM2M_SECURITY, 0)
    instAccCtrl := reg.CreateObjectInstance(oma.OBJECT_LWM2M_ACCESS_CONTROL, 0)
    instConnMon := reg.CreateObjectInstance(oma.OBJECT_LWM2M_CONNECTIVITY_MONITORING, 0)
    instConnStats := reg.CreateObjectInstance(oma.OBJECT_LWM2M_CONNECTIVITY_STATISTICS, 0)
    instFwUpdate := reg.CreateObjectInstance(oma.OBJECT_LWM2M_FIRMWARE_UPDATE, 0)
    instLocation := reg.CreateObjectInstance(oma.OBJECT_LWM2M_LOCATION, 0)
    instServer := reg.CreateObjectInstance(oma.OBJECT_LWM2M_SERVER, 0)

    client.AddObjectInstances(
        instDevice,
        instSec,
        instAccCtrl,
        instConnMon,
        instConnStats,
        instFwUpdate,
        instLocation,
        instServer,
    )

    // Check added enablers
    test_enablers := []struct {
        input   api.LWM2MObjectType
    }{
        {oma.OBJECT_LWM2M_DEVICE},
        {oma.OBJECT_LWM2M_CONNECTIVITY_STATISTICS},
        {oma.OBJECT_LWM2M_ACCESS_CONTROL},
        {oma.OBJECT_LWM2M_CONNECTIVITY_MONITORING},
        {oma.OBJECT_LWM2M_FIRMWARE_UPDATE},
        {oma.OBJECT_LWM2M_LOCATION},
        {oma.OBJECT_LWM2M_SECURITY},
        {oma.OBJECT_LWM2M_SERVER},
    }

    for _, c := range test_enablers {
        assert.NotNil(t, client.GetObjectEnabler(c.input), "Enabler returned nil", c.input)
    }

    // Device Object
    test_obj_1 := []struct {
        instanceId  int
        resourceId  int
        expected    interface{}
        typeId      api.LWM2MObjectType
    }{
        {0, 0, "Open Mobile Alliance", oma.OBJECT_LWM2M_DEVICE},
        {0, 1, "Lightweight M2M Client", oma.OBJECT_LWM2M_DEVICE},
        {0, 2, "345000123", oma.OBJECT_LWM2M_DEVICE},
        {0, 3, "1.0", oma.OBJECT_LWM2M_DEVICE},
        // {0, 6, []int{1, 5}, oma.OBJECT_LWM2M_DEVICE},
        // {0, 7, []int{3800, 5000}, oma.OBJECT_LWM2M_DEVICE},
        // {0, 8, []int{125, 900}, oma.OBJECT_LWM2M_DEVICE},
        {0, 10, 15, oma.OBJECT_LWM2M_DEVICE},
        // {0, 11, []int{0}, oma.OBJECT_LWM2M_DEVICE},
        {0, 13, time.Unix(1367491215, 0), oma.OBJECT_LWM2M_DEVICE},
        {0, 14, "+02:00", oma.OBJECT_LWM2M_DEVICE},
        {0, 16, "U", oma.OBJECT_LWM2M_DEVICE},
    }

    for _, c := range test_obj_1 {
        en := client.GetObjectEnabler(c.typeId)
        ret, _ := en.OnRead(c.instanceId, c.resourceId)
        val := ret.GetValue()

        assert.Equal(t, val, c.expected, "Unexpected value returned for enabler OnRead: ", val, "vs", c.expected)
    }
}<|endoftext|>


<commit_before>package cluster

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/docker/distribution/reference"
	apierrors "github.com/docker/docker/api/errors"
	apitypes "github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/backend"
	types "github.com/docker/docker/api/types/swarm"
	"github.com/docker/docker/daemon/cluster/convert"
	"github.com/docker/docker/daemon/logger"
	"github.com/docker/docker/pkg/ioutils"
	"github.com/docker/docker/pkg/stdcopy"
	swarmapi "github.com/docker/swarmkit/api"
	gogotypes "github.com/gogo/protobuf/types"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

// GetServices returns all services of a managed swarm cluster.
func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Service, error) {
	c.mu.RLock()
	defer c.mu.RUnlock()

	state := c.currentNodeState()
	if !state.IsActiveManager() {
		return nil, c.errNoManager(state)
	}

	filters, err := newListServicesFilters(options.Filters)
	if err != nil {
		return nil, err
	}
	ctx, cancel := c.getRequestContext()
	defer cancel()

	r, err := state.controlClient.ListServices(
		ctx,
		&swarmapi.ListServicesRequest{Filters: filters})
	if err != nil {
		return nil, err
	}

	services := []types.Service{}

	for _, service := range r.Services {
		services = append(services, convert.ServiceFromGRPC(*service))
	}

	return services, nil
}

// GetService returns a service based on an ID or name.
func (c *Cluster) GetService(input string) (types.Service, error) {
	var service *swarmapi.Service
	if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
		s, err := getService(ctx, state.controlClient, input)
		if err != nil {
			return err
		}
		service = s
		return nil
	}); err != nil {
		return types.Service{}, err
	}
	return convert.ServiceFromGRPC(*service), nil
}

// CreateService creates a new service in a managed swarm cluster.
func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string) (*apitypes.ServiceCreateResponse, error) {
	var resp *apitypes.ServiceCreateResponse
	err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
		err := c.populateNetworkID(ctx, state.controlClient, &s)
		if err != nil {
			return err
		}

		serviceSpec, err := convert.ServiceSpecToGRPC(s)
		if err != nil {
			return apierrors.NewBadRequestError(err)
		}

		ctnr := serviceSpec.Task.GetContainer()
		if ctnr == nil {
			return errors.New("service does not use container tasks")
		}

		if encodedAuth != "" {
			ctnr.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth}
		}

		// retrieve auth config from encoded auth
		authConfig := &apitypes.AuthConfig{}
		if encodedAuth != "" {
			if err := json.NewDecoder(base64.NewDecoder(base64.URLEncoding, strings.NewReader(encodedAuth))).Decode(authConfig); err != nil {
				logrus.Warnf("invalid authconfig: %v", err)
			}
		}

		resp = &apitypes.ServiceCreateResponse{}

		// pin image by digest
		if os.Getenv("DOCKER_SERVICE_PREFER_OFFLINE_IMAGE") != "1" {
			digestImage, err := c.imageWithDigestString(ctx, ctnr.Image, authConfig)
			if err != nil {
				logrus.Warnf("unable to pin image %s to digest: %s", ctnr.Image, err.Error())
				resp.Warnings = append(resp.Warnings, fmt.Sprintf("unable to pin image %s to digest: %s", ctnr.Image, err.Error()))
			} else if ctnr.Image != digestImage {
				logrus.Debugf("pinning image %s by digest: %s", ctnr.Image, digestImage)
				ctnr.Image = digestImage
			} else {
				logrus.Debugf("creating service using supplied digest reference %s", ctnr.Image)
			}
		}

		r, err := state.controlClient.CreateService(ctx, &swarmapi.CreateServiceRequest{Spec: &serviceSpec})
		if err != nil {
			return err
		}

		resp.ID = r.Service.ID
		return nil
	})
	return resp, err
}

// UpdateService updates existing service to match new properties.
func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec types.ServiceSpec, flags apitypes.ServiceUpdateOptions) (*apitypes.ServiceUpdateResponse, error) {
	var resp *apitypes.ServiceUpdateResponse

	err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {

		err := c.populateNetworkID(ctx, state.controlClient, &spec)
		if err != nil {
			return err
		}

		serviceSpec, err := convert.ServiceSpecToGRPC(spec)
		if err != nil {
			return apierrors.NewBadRequestError(err)
		}

		currentService, err := getService(ctx, state.controlClient, serviceIDOrName)
		if err != nil {
			return err
		}

		newCtnr := serviceSpec.Task.GetContainer()
		if newCtnr == nil {
			return errors.New("service does not use container tasks")
		}

		encodedAuth := flags.EncodedRegistryAuth
		if encodedAuth != "" {
			newCtnr.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth}
		} else {
			// this is needed because if the encodedAuth isn't being updated then we
			// shouldn't lose it, and continue to use the one that was already present
			var ctnr *swarmapi.ContainerSpec
			switch flags.RegistryAuthFrom {
			case apitypes.RegistryAuthFromSpec, "":
				ctnr = currentService.Spec.Task.GetContainer()
			case apitypes.RegistryAuthFromPreviousSpec:
				if currentService.PreviousSpec == nil {
					return errors.New("service does not have a previous spec")
				}
				ctnr = currentService.PreviousSpec.Task.GetContainer()
			default:
				return errors.New("unsupported registryAuthFrom value")
			}
			if ctnr == nil {
				return errors.New("service does not use container tasks")
			}
			newCtnr.PullOptions = ctnr.PullOptions
			// update encodedAuth so it can be used to pin image by digest
			if ctnr.PullOptions != nil {
				encodedAuth = ctnr.PullOptions.RegistryAuth
			}
		}

		// retrieve auth config from encoded auth
		authConfig := &apitypes.AuthConfig{}
		if encodedAuth != "" {
			if err := json.NewDecoder(base64.NewDecoder(base64.URLEncoding, strings.NewReader(encodedAuth))).Decode(authConfig); err != nil {
				logrus.Warnf("invalid authconfig: %v", err)
			}
		}

		resp := &apitypes.ServiceUpdateResponse{}

		// pin image by digest
		if os.Getenv("DOCKER_SERVICE_PREFER_OFFLINE_IMAGE") != "1" {
			digestImage, err := c.imageWithDigestString(ctx, newCtnr.Image, authConfig)
			if err != nil {
				logrus.Warnf("unable to pin image %s to digest: %s", newCtnr.Image, err.Error())
				resp.Warnings = append(resp.Warnings, fmt.Sprintf("unable to pin image %s to digest: %s", newCtnr.Image, err.Error()))
			} else if newCtnr.Image != digestImage {
				logrus.Debugf("pinning image %s by digest: %s", newCtnr.Image, digestImage)
				newCtnr.Image = digestImage
			} else {
				logrus.Debugf("updating service using supplied digest reference %s", newCtnr.Image)
			}
		}

		var rollback swarmapi.UpdateServiceRequest_Rollback
		switch flags.Rollback {
		case "", "none":
			rollback = swarmapi.UpdateServiceRequest_NONE
		case "previous":
			rollback = swarmapi.UpdateServiceRequest_PREVIOUS
		default:
			return fmt.Errorf("unrecognized rollback option %s", flags.Rollback)
		}

		_, err = state.controlClient.UpdateService(
			ctx,
			&swarmapi.UpdateServiceRequest{
				ServiceID: currentService.ID,
				Spec:      &serviceSpec,
				ServiceVersion: &swarmapi.Version{
					Index: version,
				},
				Rollback: rollback,
			},
		)
		return err
	})
	return resp, err
}

// RemoveService removes a service from a managed swarm cluster.
func (c *Cluster) RemoveService(input string) error {
	return c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
		service, err := getService(ctx, state.controlClient, input)
		if err != nil {
			return err
		}

		_, err = state.controlClient.RemoveService(ctx, &swarmapi.RemoveServiceRequest{ServiceID: service.ID})
		return err
	})
}

// ServiceLogs collects service logs and writes them back to `config.OutStream`
func (c *Cluster) ServiceLogs(ctx context.Context, input string, config *backend.ContainerLogsConfig, started chan struct{}) error {
	c.mu.RLock()
	state := c.currentNodeState()
	if !state.IsActiveManager() {
		c.mu.RUnlock()
		return c.errNoManager(state)
	}

	service, err := getService(ctx, state.controlClient, input)
	if err != nil {
		c.mu.RUnlock()
		return err
	}

	// set the streams we'll use
	stdStreams := []swarmapi.LogStream{}
	if config.ContainerLogsOptions.ShowStdout {
		stdStreams = append(stdStreams, swarmapi.LogStreamStdout)
	}
	if config.ContainerLogsOptions.ShowStderr {
		stdStreams = append(stdStreams, swarmapi.LogStreamStderr)
	}

	stream, err := state.logsClient.SubscribeLogs(ctx, &swarmapi.SubscribeLogsRequest{
		Selector: &swarmapi.LogSelector{
			ServiceIDs: []string{service.ID},
		},
		Options: &swarmapi.LogSubscriptionOptions{
			Follow:  config.Follow,
			Streams: stdStreams,
		},
	})
	if err != nil {
		c.mu.RUnlock()
		return err
	}

	wf := ioutils.NewWriteFlusher(config.OutStream)
	defer wf.Close()
	close(started)
	wf.Flush()

	outStream := stdcopy.NewStdWriter(wf, stdcopy.Stdout)
	errStream := stdcopy.NewStdWriter(wf, stdcopy.Stderr)

	// Release the lock before starting the stream.
	c.mu.RUnlock()
	for {
		// Check the context before doing anything.
		select {
		case <-ctx.Done():
			return ctx.Err()
		default:
		}

		subscribeMsg, err := stream.Recv()
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}

		for _, msg := range subscribeMsg.Messages {
			data := []byte{}

			if config.Timestamps {
				ts, err := gogotypes.TimestampFromProto(msg.Timestamp)
				if err != nil {
					return err
				}
				data = append(data, []byte(ts.Format(logger.TimeFormat)+" ")...)
			}

			data = append(data, []byte(fmt.Sprintf("%s.node.id=%s,%s.service.id=%s,%s.task.id=%s ",
				contextPrefix, msg.Context.NodeID,
				contextPrefix, msg.Context.ServiceID,
				contextPrefix, msg.Context.TaskID,
			))...)

			data = append(data, msg.Data...)

			switch msg.Stream {
			case swarmapi.LogStreamStdout:
				outStream.Write(data)
			case swarmapi.LogStreamStderr:
				errStream.Write(data)
			}
		}
	}
}

// imageWithDigestString takes an image such as name or name:tag
// and returns the image pinned to a digest, such as name@sha256:34234
func (c *Cluster) imageWithDigestString(ctx context.Context, image string, authConfig *apitypes.AuthConfig) (string, error) {
	ref, err := reference.ParseAnyReference(image)
	if err != nil {
		return "", err
	}
	namedRef, ok := ref.(reference.Named)
	if !ok {
		if _, ok := ref.(reference.Digested); ok {
			return "", errors.New("image reference is an image ID")
		}
		return "", errors.Errorf("unknown image reference format: %s", image)
	}
	// only query registry if not a canonical reference (i.e. with digest)
	if _, ok := namedRef.(reference.Canonical); !ok {
		namedRef = reference.TagNameOnly(namedRef)

		taggedRef, ok := namedRef.(reference.NamedTagged)
		if !ok {
			return "", errors.Errorf("image reference not tagged: %s", image)
		}

		repo, _, err := c.config.Backend.GetRepository(ctx, taggedRef, authConfig)
		if err != nil {
			return "", err
		}
		dscrptr, err := repo.Tags(ctx).Get(ctx, taggedRef.Tag())
		if err != nil {
			return "", err
		}

		namedDigestedRef, err := reference.WithDigest(taggedRef, dscrptr.Digest)
		if err != nil {
			return "", err
		}
		// return familiar form until interface updated to return type
		return reference.FamiliarString(namedDigestedRef), nil
	}
	// reference already contains a digest, so just return it
	return reference.FamiliarString(ref), nil
}
<commit_msg>cluster: Fix shadowed resp variable<commit_after>package cluster

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/docker/distribution/reference"
	apierrors "github.com/docker/docker/api/errors"
	apitypes "github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/backend"
	types "github.com/docker/docker/api/types/swarm"
	"github.com/docker/docker/daemon/cluster/convert"
	"github.com/docker/docker/daemon/logger"
	"github.com/docker/docker/pkg/ioutils"
	"github.com/docker/docker/pkg/stdcopy"
	swarmapi "github.com/docker/swarmkit/api"
	gogotypes "github.com/gogo/protobuf/types"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

// GetServices returns all services of a managed swarm cluster.
func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Service, error) {
	c.mu.RLock()
	defer c.mu.RUnlock()

	state := c.currentNodeState()
	if !state.IsActiveManager() {
		return nil, c.errNoManager(state)
	}

	filters, err := newListServicesFilters(options.Filters)
	if err != nil {
		return nil, err
	}
	ctx, cancel := c.getRequestContext()
	defer cancel()

	r, err := state.controlClient.ListServices(
		ctx,
		&swarmapi.ListServicesRequest{Filters: filters})
	if err != nil {
		return nil, err
	}

	services := []types.Service{}

	for _, service := range r.Services {
		services = append(services, convert.ServiceFromGRPC(*service))
	}

	return services, nil
}

// GetService returns a service based on an ID or name.
func (c *Cluster) GetService(input string) (types.Service, error) {
	var service *swarmapi.Service
	if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
		s, err := getService(ctx, state.controlClient, input)
		if err != nil {
			return err
		}
		service = s
		return nil
	}); err != nil {
		return types.Service{}, err
	}
	return convert.ServiceFromGRPC(*service), nil
}

// CreateService creates a new service in a managed swarm cluster.
func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string) (*apitypes.ServiceCreateResponse, error) {
	var resp *apitypes.ServiceCreateResponse
	err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
		err := c.populateNetworkID(ctx, state.controlClient, &s)
		if err != nil {
			return err
		}

		serviceSpec, err := convert.ServiceSpecToGRPC(s)
		if err != nil {
			return apierrors.NewBadRequestError(err)
		}

		ctnr := serviceSpec.Task.GetContainer()
		if ctnr == nil {
			return errors.New("service does not use container tasks")
		}

		if encodedAuth != "" {
			ctnr.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth}
		}

		// retrieve auth config from encoded auth
		authConfig := &apitypes.AuthConfig{}
		if encodedAuth != "" {
			if err := json.NewDecoder(base64.NewDecoder(base64.URLEncoding, strings.NewReader(encodedAuth))).Decode(authConfig); err != nil {
				logrus.Warnf("invalid authconfig: %v", err)
			}
		}

		resp = &apitypes.ServiceCreateResponse{}

		// pin image by digest
		if os.Getenv("DOCKER_SERVICE_PREFER_OFFLINE_IMAGE") != "1" {
			digestImage, err := c.imageWithDigestString(ctx, ctnr.Image, authConfig)
			if err != nil {
				logrus.Warnf("unable to pin image %s to digest: %s", ctnr.Image, err.Error())
				resp.Warnings = append(resp.Warnings, fmt.Sprintf("unable to pin image %s to digest: %s", ctnr.Image, err.Error()))
			} else if ctnr.Image != digestImage {
				logrus.Debugf("pinning image %s by digest: %s", ctnr.Image, digestImage)
				ctnr.Image = digestImage
			} else {
				logrus.Debugf("creating service using supplied digest reference %s", ctnr.Image)
			}
		}

		r, err := state.controlClient.CreateService(ctx, &swarmapi.CreateServiceRequest{Spec: &serviceSpec})
		if err != nil {
			return err
		}

		resp.ID = r.Service.ID
		return nil
	})
	return resp, err
}

// UpdateService updates existing service to match new properties.
func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec types.ServiceSpec, flags apitypes.ServiceUpdateOptions) (*apitypes.ServiceUpdateResponse, error) {
	var resp *apitypes.ServiceUpdateResponse

	err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {

		err := c.populateNetworkID(ctx, state.controlClient, &spec)
		if err != nil {
			return err
		}

		serviceSpec, err := convert.ServiceSpecToGRPC(spec)
		if err != nil {
			return apierrors.NewBadRequestError(err)
		}

		currentService, err := getService(ctx, state.controlClient, serviceIDOrName)
		if err != nil {
			return err
		}

		newCtnr := serviceSpec.Task.GetContainer()
		if newCtnr == nil {
			return errors.New("service does not use container tasks")
		}

		encodedAuth := flags.EncodedRegistryAuth
		if encodedAuth != "" {
			newCtnr.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth}
		} else {
			// this is needed because if the encodedAuth isn't being updated then we
			// shouldn't lose it, and continue to use the one that was already present
			var ctnr *swarmapi.ContainerSpec
			switch flags.RegistryAuthFrom {
			case apitypes.RegistryAuthFromSpec, "":
				ctnr = currentService.Spec.Task.GetContainer()
			case apitypes.RegistryAuthFromPreviousSpec:
				if currentService.PreviousSpec == nil {
					return errors.New("service does not have a previous spec")
				}
				ctnr = currentService.PreviousSpec.Task.GetContainer()
			default:
				return errors.New("unsupported registryAuthFrom value")
			}
			if ctnr == nil {
				return errors.New("service does not use container tasks")
			}
			newCtnr.PullOptions = ctnr.PullOptions
			// update encodedAuth so it can be used to pin image by digest
			if ctnr.PullOptions != nil {
				encodedAuth = ctnr.PullOptions.RegistryAuth
			}
		}

		// retrieve auth config from encoded auth
		authConfig := &apitypes.AuthConfig{}
		if encodedAuth != "" {
			if err := json.NewDecoder(base64.NewDecoder(base64.URLEncoding, strings.NewReader(encodedAuth))).Decode(authConfig); err != nil {
				logrus.Warnf("invalid authconfig: %v", err)
			}
		}

		resp = &apitypes.ServiceUpdateResponse{}

		// pin image by digest
		if os.Getenv("DOCKER_SERVICE_PREFER_OFFLINE_IMAGE") != "1" {
			digestImage, err := c.imageWithDigestString(ctx, newCtnr.Image, authConfig)
			if err != nil {
				logrus.Warnf("unable to pin image %s to digest: %s", newCtnr.Image, err.Error())
				resp.Warnings = append(resp.Warnings, fmt.Sprintf("unable to pin image %s to digest: %s", newCtnr.Image, err.Error()))
			} else if newCtnr.Image != digestImage {
				logrus.Debugf("pinning image %s by digest: %s", newCtnr.Image, digestImage)
				newCtnr.Image = digestImage
			} else {
				logrus.Debugf("updating service using supplied digest reference %s", newCtnr.Image)
			}
		}

		var rollback swarmapi.UpdateServiceRequest_Rollback
		switch flags.Rollback {
		case "", "none":
			rollback = swarmapi.UpdateServiceRequest_NONE
		case "previous":
			rollback = swarmapi.UpdateServiceRequest_PREVIOUS
		default:
			return fmt.Errorf("unrecognized rollback option %s", flags.Rollback)
		}

		_, err = state.controlClient.UpdateService(
			ctx,
			&swarmapi.UpdateServiceRequest{
				ServiceID: currentService.ID,
				Spec:      &serviceSpec,
				ServiceVersion: &swarmapi.Version{
					Index: version,
				},
				Rollback: rollback,
			},
		)
		return err
	})
	return resp, err
}

// RemoveService removes a service from a managed swarm cluster.
func (c *Cluster) RemoveService(input string) error {
	return c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
		service, err := getService(ctx, state.controlClient, input)
		if err != nil {
			return err
		}

		_, err = state.controlClient.RemoveService(ctx, &swarmapi.RemoveServiceRequest{ServiceID: service.ID})
		return err
	})
}

// ServiceLogs collects service logs and writes them back to `config.OutStream`
func (c *Cluster) ServiceLogs(ctx context.Context, input string, config *backend.ContainerLogsConfig, started chan struct{}) error {
	c.mu.RLock()
	state := c.currentNodeState()
	if !state.IsActiveManager() {
		c.mu.RUnlock()
		return c.errNoManager(state)
	}

	service, err := getService(ctx, state.controlClient, input)
	if err != nil {
		c.mu.RUnlock()
		return err
	}

	// set the streams we'll use
	stdStreams := []swarmapi.LogStream{}
	if config.ContainerLogsOptions.ShowStdout {
		stdStreams = append(stdStreams, swarmapi.LogStreamStdout)
	}
	if config.ContainerLogsOptions.ShowStderr {
		stdStreams = append(stdStreams, swarmapi.LogStreamStderr)
	}

	stream, err := state.logsClient.SubscribeLogs(ctx, &swarmapi.SubscribeLogsRequest{
		Selector: &swarmapi.LogSelector{
			ServiceIDs: []string{service.ID},
		},
		Options: &swarmapi.LogSubscriptionOptions{
			Follow:  config.Follow,
			Streams: stdStreams,
		},
	})
	if err != nil {
		c.mu.RUnlock()
		return err
	}

	wf := ioutils.NewWriteFlusher(config.OutStream)
	defer wf.Close()
	close(started)
	wf.Flush()

	outStream := stdcopy.NewStdWriter(wf, stdcopy.Stdout)
	errStream := stdcopy.NewStdWriter(wf, stdcopy.Stderr)

	// Release the lock before starting the stream.
	c.mu.RUnlock()
	for {
		// Check the context before doing anything.
		select {
		case <-ctx.Done():
			return ctx.Err()
		default:
		}

		subscribeMsg, err := stream.Recv()
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}

		for _, msg := range subscribeMsg.Messages {
			data := []byte{}

			if config.Timestamps {
				ts, err := gogotypes.TimestampFromProto(msg.Timestamp)
				if err != nil {
					return err
				}
				data = append(data, []byte(ts.Format(logger.TimeFormat)+" ")...)
			}

			data = append(data, []byte(fmt.Sprintf("%s.node.id=%s,%s.service.id=%s,%s.task.id=%s ",
				contextPrefix, msg.Context.NodeID,
				contextPrefix, msg.Context.ServiceID,
				contextPrefix, msg.Context.TaskID,
			))...)

			data = append(data, msg.Data...)

			switch msg.Stream {
			case swarmapi.LogStreamStdout:
				outStream.Write(data)
			case swarmapi.LogStreamStderr:
				errStream.Write(data)
			}
		}
	}
}

// imageWithDigestString takes an image such as name or name:tag
// and returns the image pinned to a digest, such as name@sha256:34234
func (c *Cluster) imageWithDigestString(ctx context.Context, image string, authConfig *apitypes.AuthConfig) (string, error) {
	ref, err := reference.ParseAnyReference(image)
	if err != nil {
		return "", err
	}
	namedRef, ok := ref.(reference.Named)
	if !ok {
		if _, ok := ref.(reference.Digested); ok {
			return "", errors.New("image reference is an image ID")
		}
		return "", errors.Errorf("unknown image reference format: %s", image)
	}
	// only query registry if not a canonical reference (i.e. with digest)
	if _, ok := namedRef.(reference.Canonical); !ok {
		namedRef = reference.TagNameOnly(namedRef)

		taggedRef, ok := namedRef.(reference.NamedTagged)
		if !ok {
			return "", errors.Errorf("image reference not tagged: %s", image)
		}

		repo, _, err := c.config.Backend.GetRepository(ctx, taggedRef, authConfig)
		if err != nil {
			return "", err
		}
		dscrptr, err := repo.Tags(ctx).Get(ctx, taggedRef.Tag())
		if err != nil {
			return "", err
		}

		namedDigestedRef, err := reference.WithDigest(taggedRef, dscrptr.Digest)
		if err != nil {
			return "", err
		}
		// return familiar form until interface updated to return type
		return reference.FamiliarString(namedDigestedRef), nil
	}
	// reference already contains a digest, so just return it
	return reference.FamiliarString(ref), nil
}
<|endoftext|>


<commit_before>package config

import (
	"os"
	"encoding/json"
	"log"
	"github.com/xsank/EasyProxy/src/structure"
)

type Config struct {
	Service      string `json:"service"`
	Host         string `json:"host"`
	Port         uint16 `json:"port"`
	WebPort      uint16 `json:"webport"`
	Strategy     string `json:"strategy"`
	Heartbeat    int `json:"heartbeat"`
	MaxProcessor int `json:"maxprocessor"`
	Backends     []structure.Backend `json:"backends"`
}

func Load(filename string) (*Config, error) {
	var config Config
	file, err := os.Open(filename)
	if err != nil {
		log.Println("load config failed:", err)
	} else {
		buff := make([]byte, 1024)
		end, _ := file.Read(buff)
		err = json.Unmarshal(buff[:end], &config)
		if err != nil {
			log.Println("decode json config failed:", err)
		}
	}
	log.Println("success load config file:", filename)
	return &config, err
}

<commit_msg>修正配置文件大于1k时加载问题<commit_after>package config

import (
	"encoding/json"
	"log"
	"github.com/xsank/EasyProxy/src/structure"
	"io/ioutil"
)

type Config struct {
	Service      string `json:"service"`
	Host         string `json:"host"`
	Port         uint16 `json:"port"`
	WebPort      uint16 `json:"webport"`
	Strategy     string `json:"strategy"`
	Heartbeat    int `json:"heartbeat"`
	MaxProcessor int `json:"maxprocessor"`
	Backends     []structure.Backend `json:"backends"`
}

func Load(filename string) (*Config, error) {
	var config Config
	file, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Println("load config failed:", err)
	} else {
		err = json.Unmarshal(file, &config)
		if err != nil {
			log.Println("xdecode json config failed:", err)
		}
	}
	log.Println("success load config file:", filename)
	return &config, err
}

<|endoftext|>


<commit_before>/*
Copyright 2011 Google Inc.

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.
*/

// runsit runs stuff.
//
// Author: Brad Fitzpatrick <brad@danga.com>

package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"os/exec"
	"strconv"
	"sync"
	"time"

	"danga.com/runsit/jsonconfig"
)

// Flags.
var (
	httpPort  = flag.Int("http_port", 4762, "HTTP localhost admin port.")
	configDir = flag.String("config_dir", "config", "Directory containing per-task *.json config files.")
)

var (
	// TODO: log to multiwriter of stderr and ringbuffer, or maybe just
	// ringbuffer depending on the environment.
	logger = log.New(os.Stderr, "", log.Lmicroseconds|log.Lshortfile)

	tasksMu sync.Mutex
	tasks   = make(map[string]*Task)
)

type Task struct {
	Name     string
	controlc chan interface{}

	// State owned by loop's goroutine:
	config    jsonconfig.Obj // last valid config
	cmd       *exec.Cmd
	lastStart time.Time
}

func NewTask(name string) *Task {
	t := &Task{
		Name:     name,
		controlc: make(chan interface{}),
	}
	go t.loop()
	return t
}

func (t *Task) Printf(format string, args ...interface{}) {
	logger.Printf(fmt.Sprintf("Task %q: %s", t.Name, format), args...)
}

func (t *Task) loop() {
	t.Printf("Starting")
	for cm := range t.controlc {
		switch m := cm.(type) {
		case statusRequestMessage:
			m.resCh <- t.status()
		case updateMessage:
			t.update(m.tf)
		case stopMessage:
			t.stop()
		case outputMessage:
			t.Printf("Got output: %#v", m)
		case waitMessage:
			t.onTaskFinished(m)
		}
	}
}

type waitMessage struct {
	cmd *exec.Cmd
	err error // return from cmd.Wait(), nil, *exec.ExitError, or other type
}

type outputMessage struct {
	cmd      *exec.Cmd // instance of command that spoke
	name     string    // "stdout" or "stderr"
	isPrefix bool      // truncated line? (too long)
	data     string    // line or prefix of line
}

type updateMessage struct {
	tf TaskFile
}

type stopMessage struct{}

type statusRequestMessage struct {
	resCh chan<- string
}

func (t *Task) Update(tf TaskFile) {
	t.controlc <- updateMessage{tf}
}

// run in Task.loop
func (t *Task) onTaskFinished(m waitMessage) {
	t.Printf("Task exited; err=%v", m.err)
	if m.cmd == t.cmd {
		t.cmd = nil
	}
	if m.err == nil {
		// TODO: vary sleep time (but not in this goroutine)
		// based on how process ended and when it was last
		// started (prevent crash/restart loops)
	}
	if t.config != nil {
		t.Printf("Restarting")
		t.updateFromConfig(t.config)
	}
}

// run in Task.loop
func (t *Task) update(tf TaskFile) {
	t.config = nil
	jc, err := jsonconfig.ReadFile(tf.ConfigFileName())
	t.stop()
	if err != nil {
		t.Printf("Bad config file: %v", err)
		return
	}
	t.updateFromConfig(jc)
}

// run in Task.loop
func (t *Task) updateFromConfig(jc jsonconfig.Obj) {
	t.config = nil
	t.stop()

	ports := jc.OptionalObject("ports")
	_ = ports
	user := jc.OptionalString("user", "")
	curUser := os.Getenv("USER")
	if user == "" {
		user = curUser
	}
	if user != curUser {
		panic("TODO: switch user")
	}

	env := []string{}
	stdEnv := jc.OptionalBool("standardEnv", true)
	if stdEnv {
		env = append(env, fmt.Sprintf("USER=%s", user))
	}
	envMap := jc.OptionalObject("env")
	for k, v := range envMap {
		env = append(env, fmt.Sprintf("%s=%s", k, v))
	}

	bin := jc.RequiredString("binary")
	cwd := jc.OptionalString("cwd", "")
	args := jc.OptionalList("args")
	if err := jc.Validate(); err != nil {
		t.Printf("configuration error: %v", err)
		return
	}

	_, err := os.Stat(bin)
	if err != nil {
		t.Printf("stat of binary %q failed: %v", bin, err)
		return
	}

	t.config = jc

	cmd := exec.Command(bin, args...)
	cmd.Dir = cwd
	cmd.Env = env

	outPipe, err := cmd.StdoutPipe()
	if err != nil {
		t.Printf("StdoutPipe: %v", err)
		return
	}
	errPipe, err := cmd.StderrPipe()
	if err != nil {
		t.Printf("StderrPipe: %v", err)
		outPipe.Close()
		return
	}

	t.lastStart = time.Now()
	err = cmd.Start()
	if err != nil {
		outPipe.Close()
		errPipe.Close()
		t.Printf("Error starting: %v", err)
		return
	}
	t.cmd = cmd
	go t.watchPipe(cmd, outPipe, "stdout")
	go t.watchPipe(cmd, errPipe, "stderr")
	go t.watchCommand(cmd)
}

// run in its own goroutine
func (t *Task) watchCommand(cmd *exec.Cmd) {
	err := cmd.Wait()
	t.controlc <- waitMessage{cmd: cmd, err: err}
}

// run in its own goroutine
func (t *Task) watchPipe(cmd *exec.Cmd, r io.Reader, name string) {
	br := bufio.NewReader(r)
	for {
		sl, isPrefix, err := br.ReadLine()
		if err != nil {
			t.Printf("pipe %q closed: %v", name, err)
			return
		}
		t.controlc <- outputMessage{
			cmd:      cmd,
			name:     name,
			isPrefix: isPrefix,
			data:     string(sl),
		}
	}
	panic("unreachable")
}

func (t *Task) Stop() {
	t.controlc <- stopMessage{}
}

// runs in Task.loop
func (t *Task) stop() {
	if t.cmd == nil {
		return
	}
	t.Printf("sending SIGKILL")
	// TODO: more graceful kill types
	t.cmd.Process.Kill()
	t.cmd = nil
}

func (t *Task) Status() string {
	ch := make(chan string, 1)
	t.controlc <- statusRequestMessage{resCh: ch}
	return <-ch
}

// runs in Task.loop
func (t *Task) status() string {
	if t.cmd != nil {
		d := time.Now().Sub(t.lastStart)
		return fmt.Sprintf("running; for %v", d)
	}
	if t.config == nil {
		return "not running, no valid config"
	}
	// TODO: flesh these not running states out.
	// e.g. intentionaly stopped, how long we're pausing before
	// next re-start attempt, etc.
	return "not running; valid config"
}

func watchConfigDir() {
	for tf := range dirWatcher().Updates() {
		t := GetOrMakeTask(tf.Name())
		go t.Update(tf)
	}
}

func GetTask(name string) (*Task, bool) {
	tasksMu.Lock()
	defer tasksMu.Unlock()
	t, ok := tasks[name]
	return t, ok
}

// GetOrMakeTask returns or create the named task.
func GetOrMakeTask(name string) *Task {
	tasksMu.Lock()
	defer tasksMu.Unlock()
	t, ok := tasks[name]
	if !ok {
		t = NewTask(name)
		tasks[name] = t
	}
	return t
}

// GetTasks returns all known tasks.
func GetTasks() []*Task {
	ts := []*Task{}
	tasksMu.Lock()
	defer tasksMu.Unlock()
	for _, t := range tasks {
		ts = append(ts, t)
	}
	return ts
}

func main() {
	flag.Parse()

	ln, err := net.Listen("tcp", "localhost:"+strconv.Itoa(*httpPort))
	if err != nil {
		logger.Printf("Error listening on port %d: %v", *httpPort, err)
		os.Exit(1)
		return
	}
	logger.Printf("Listening on port %d", *httpPort)

	go watchConfigDir()
	go runWebServer(ln)
	select {}
}
<commit_msg>Task/TaskInstance split<commit_after>/*
Copyright 2011 Google Inc.

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.
*/

// runsit runs stuff.
//
// Author: Brad Fitzpatrick <brad@danga.com>

package main

import (
	"bufio"
	"container/list"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"os/exec"
	"strconv"
	"sync"
	"time"

	"danga.com/runsit/jsonconfig"
)

// Flags.
var (
	httpPort  = flag.Int("http_port", 4762, "HTTP localhost admin port.")
	configDir = flag.String("config_dir", "config", "Directory containing per-task *.json config files.")
)

var (
	// TODO: log to multiwriter of stderr and ringbuffer, or maybe just
	// ringbuffer depending on the environment.
	logger = log.New(os.Stderr, "", log.Lmicroseconds|log.Lshortfile)

	tasksMu sync.Mutex
	tasks   = make(map[string]*Task)
)

// A Task is a named daemon. A single instance of Task exists for the
// life of the runsit daemon, despite how many times the task has
// failed and restarted.
type Task struct {
	// Immutable:
	Name     string
	controlc chan interface{}

	// State owned by loop's goroutine:
	config   jsonconfig.Obj // last valid config
	running  *TaskInstance
	failures []*TaskInstance // last few failures, oldest first.
}

// TaskInstance is a particular instance of a running Task.
type TaskInstance struct {
	task      *Task
	config    jsonconfig.Obj
	cmd       *exec.Cmd
	startTime time.Time
	output    TaskOutput
}

// ID returns a unique ID string for this task instance.
func (in *TaskInstance) ID() string {
	// TODO: include pid if available
	return fmt.Sprintf("%s/%d", in.task.Name, in.startTime.Unix())
}

func (in *TaskInstance) Printf(format string, args ...interface{}) {
	logger.Printf(fmt.Sprintf("Task %s: %s", in.ID(), format), args...)
}

type TaskOutput struct {
	lines *list.List // of *outputMessage
}

func NewTask(name string) *Task {
	t := &Task{
		Name:     name,
		controlc: make(chan interface{}),
	}
	go t.loop()
	return t
}

func (t *Task) Printf(format string, args ...interface{}) {
	logger.Printf(fmt.Sprintf("Task %q: %s", t.Name, format), args...)
}

func (t *Task) loop() {
	t.Printf("Starting")
	for cm := range t.controlc {
		switch m := cm.(type) {
		case statusRequestMessage:
			m.resCh <- t.status()
		case updateMessage:
			t.update(m.tf)
		case stopMessage:
			t.stop()
		case *outputMessage:
			t.Printf("Got output: %#v", *m)
		case waitMessage:
			t.onTaskFinished(m)
		}
	}
}

type waitMessage struct {
	instance *TaskInstance
	err      error // return from cmd.Wait(), nil, *exec.ExitError, or other type
}

type outputMessage struct {
	t        time.Time
	instance *TaskInstance
	name     string // "stdout" or "stderr"
	isPrefix bool   // truncated line? (too long)
	data     string // line or prefix of line
}

type updateMessage struct {
	tf TaskFile
}

type stopMessage struct{}

type statusRequestMessage struct {
	resCh chan<- string
}

func (t *Task) Update(tf TaskFile) {
	t.controlc <- updateMessage{tf}
}

// run in Task.loop
func (t *Task) onTaskFinished(m waitMessage) {
	t.Printf("Task exited; err=%v", m.err)
	if m.instance == t.running {
		t.running = nil
	}
	const keepFailures = 5
	if len(t.failures) == keepFailures {
		copy(t.failures, t.failures[1:])
		t.failures = t.failures[:keepFailures-1]
	}
	t.failures = append(t.failures, m.instance)

	if m.err == nil {
		// TODO: vary sleep time (but not in this goroutine)
		// based on how process ended and when it was last
		// started (prevent crash/restart loops)
	}
	if t.config != nil {
		t.Printf("Restarting")
		t.updateFromConfig(t.config)
	}
}

// run in Task.loop
func (t *Task) update(tf TaskFile) {
	t.config = nil
	jc, err := jsonconfig.ReadFile(tf.ConfigFileName())
	t.stop()
	if err != nil {
		t.Printf("Bad config file: %v", err)
		return
	}
	t.updateFromConfig(jc)
}

// run in Task.loop
func (t *Task) updateFromConfig(jc jsonconfig.Obj) {
	t.config = nil
	t.stop()

	ports := jc.OptionalObject("ports")
	_ = ports
	user := jc.OptionalString("user", "")
	curUser := os.Getenv("USER")
	if user == "" {
		user = curUser
	}
	if user != curUser {
		panic("TODO: switch user")
	}

	env := []string{}
	stdEnv := jc.OptionalBool("standardEnv", true)
	if stdEnv {
		env = append(env, fmt.Sprintf("USER=%s", user))
	}
	envMap := jc.OptionalObject("env")
	for k, v := range envMap {
		env = append(env, fmt.Sprintf("%s=%s", k, v))
	}

	bin := jc.RequiredString("binary")
	cwd := jc.OptionalString("cwd", "")
	args := jc.OptionalList("args")
	if err := jc.Validate(); err != nil {
		t.Printf("configuration error: %v", err)
		return
	}
	t.config = jc

	_, err := os.Stat(bin)
	if err != nil {
		t.Printf("stat of binary %q failed: %v", bin, err)
		return
	}

	instance := &TaskInstance{
		task:      t,
		config:    jc,
		startTime: time.Now(),
		cmd:       exec.Command(bin, args...),
	}

	cmd := instance.cmd
	cmd.Dir = cwd
	cmd.Env = env

	outPipe, err := cmd.StdoutPipe()
	if err != nil {
		t.Printf("StdoutPipe: %v", err)
		return
	}
	errPipe, err := cmd.StderrPipe()
	if err != nil {
		t.Printf("StderrPipe: %v", err)
		outPipe.Close()
		return
	}

	err = cmd.Start()
	if err != nil {
		outPipe.Close()
		errPipe.Close()
		t.Printf("Error starting: %v", err)
		return
	}
	t.running = instance
	go instance.watchPipe(outPipe, "stdout")
	go instance.watchPipe(errPipe, "stderr")
	go instance.awaitDeath()
}

// run in its own goroutine
func (in *TaskInstance) awaitDeath() {
	err := in.cmd.Wait()
	in.task.controlc <- waitMessage{instance: in, err: err}
}

// run in its own goroutine
func (in *TaskInstance) watchPipe(r io.Reader, name string) {
	br := bufio.NewReader(r)
	for {
		sl, isPrefix, err := br.ReadLine()
		if err != nil {
			in.Printf("pipe %q closed: %v", name, err)
			return
		}
		in.task.controlc <- &outputMessage{
			t:        time.Now(),
			instance: in,
			name:     name,
			isPrefix: isPrefix,
			data:     string(sl),
		}
	}
	panic("unreachable")
}

func (t *Task) Stop() {
	t.controlc <- stopMessage{}
}

// runs in Task.loop
func (t *Task) stop() {
	in := t.running
	if in == nil {
		return
	}
	in.Printf("sending SIGKILL")
	// TODO: more graceful kill types
	in.cmd.Process.Kill()
	t.running = nil
}

func (t *Task) Status() string {
	ch := make(chan string, 1)
	t.controlc <- statusRequestMessage{resCh: ch}
	return <-ch
}

// runs in Task.loop
func (t *Task) status() string {
	in := t.running
	if in != nil {
		d := time.Now().Sub(in.startTime)
		return fmt.Sprintf("running; for %v", d)
	}
	if t.config == nil {
		return "not running, no valid config"
	}
	// TODO: flesh these not running states out.
	// e.g. intentionaly stopped, how long we're pausing before
	// next re-start attempt, etc.
	return "not running; valid config"
}

func watchConfigDir() {
	for tf := range dirWatcher().Updates() {
		t := GetOrMakeTask(tf.Name())
		go t.Update(tf)
	}
}

func GetTask(name string) (*Task, bool) {
	tasksMu.Lock()
	defer tasksMu.Unlock()
	t, ok := tasks[name]
	return t, ok
}

// GetOrMakeTask returns or create the named task.
func GetOrMakeTask(name string) *Task {
	tasksMu.Lock()
	defer tasksMu.Unlock()
	t, ok := tasks[name]
	if !ok {
		t = NewTask(name)
		tasks[name] = t
	}
	return t
}

// GetTasks returns all known tasks.
func GetTasks() []*Task {
	ts := []*Task{}
	tasksMu.Lock()
	defer tasksMu.Unlock()
	for _, t := range tasks {
		ts = append(ts, t)
	}
	return ts
}

func main() {
	flag.Parse()

	ln, err := net.Listen("tcp", "localhost:"+strconv.Itoa(*httpPort))
	if err != nil {
		logger.Printf("Error listening on port %d: %v", *httpPort, err)
		os.Exit(1)
		return
	}
	logger.Printf("Listening on port %d", *httpPort)

	go watchConfigDir()
	go runWebServer(ln)
	select {}
}
<|endoftext|>


<commit_before>//  Copyright 2015 Elrich Groenewald
//
//  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.

// 	The mount package provides methods to mount marshaled protocol buffers as a filesystem.
package mount

import (
	"fmt"
	"log"
	"strings"
	"os/signal"
	"os"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"

	"github.com/elrichgro/protofuse/unmarshal"
	"github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
)

//	Mounts a marshaled protocol buffer as a filesytem.
func Mount(marshaled []byte, fileDesc *google_protobuf.FileDescriptorSet, packageName string, messageName string, mountPoint string) error {
	// mount
	c, err := fuse.Mount(
		mountPoint,
		fuse.FSName("protofuse"),
		fuse.Subtype("protofs"),
		fuse.LocalVolume(),
		fuse.VolumeName("ProtoFS"),
	)
	if err != nil {
		return err
	}
	defer c.Close()

	// unmount filesystem in the event of an interrupt
	c1 := make(chan os.Signal, 1)
	signal.Notify(c1, os.Interrupt)
	go func(){
    for sig := range c1 {
    	log.Printf("captured %v, unmounting filesystem", sig)
        defer os.Exit(1)
        err = fuse.Unmount(mountPoint)
		if err != nil {
			log.Panic(err)
		}
    }
	}()

	// create the filesystem structure
	PT, err := unmarshal.Unmarshal(fileDesc, packageName, messageName, [][]byte{marshaled})
	if err != nil {
		return err
	}

	// serve
	err = fs.Serve(c, PT)
	if err != nil {
		return err
	}
	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; err != nil {
		return err
	}

	return nil
}

// Mounts a list of marshaled protocol buffers as a filesystem.
func MountList(marshaled [][]byte, fileDesc *google_protobuf.FileDescriptorSet, packageName string, messageName string, mountPoint string) error {
	// mount
	c, err := fuse.Mount(
		mountPoint,
		fuse.FSName("protofuse"),
		fuse.Subtype("protofs"),
		fuse.LocalVolume(),
		fuse.VolumeName("ProtoFS"),
	)
	if err != nil {
		return err
	}
	defer c.Close()

	// unmount the filesystem in the event of an interrupt
	c1 := make(chan os.Signal, 1)
	signal.Notify(c1, os.Interrupt)
	go func(){
    for sig := range c1 {
    	log.Printf("captured %v, unmounting filesystem", sig)
        err = fuse.Unmount(mountPoint)
		if err != nil {
			log.Panic(err)
		}
    }
	}()

	// create the filesystem structure
	PT, err := unmarshal.Unmarshal(fileDesc, packageName, messageName, marshaled)
	if err != nil {
		return err
	}

	// serve
	err = fs.Serve(c, PT)
	if err != nil {
		return err
	}

	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; err != nil {
		return err
	}

	return nil
}

// Tries to unmount the filesystem at dir.
func Unmount(dir string) error {
	err := fuse.Unmount(dir)
	if err != nil {
		return err
	}
	return nil
}

// Finds the google_protobuf.DescriptorProto for the message name.
func getDescriptorProto(name string, fileDesc *google_protobuf.FileDescriptorSet) (*google_protobuf.DescriptorProto, error) {
	if string(name[0]) == "." {
		s := strings.Split(name, ".")
		slen := len(s)
		for _, file := range fileDesc.File {
			if file.GetPackage() == s[1] {
				for _, message := range file.MessageType {
					if message.GetName() == s[2] {
						if slen <= 3 {
							return message, nil
						}
						var m *google_protobuf.DescriptorProto = message

						for i := 3; i < slen; i++ {
							for _, d := range m.GetNestedType() {
								if d.GetName() == s[i] {
									if i >= slen-1 {
										return d, nil
									}
									m = d
								}
							}
						}
						return nil, fmt.Errorf("Cannot find message1: %s", name)
					}
				}
			}
		}
		return nil, fmt.Errorf("Cannot find message: %s", name)
	}
	return nil, fmt.Errorf("Message name not fully qualified: %s", name)
}
<commit_msg>Unmount error<commit_after>//  Copyright 2015 Elrich Groenewald
//
//  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.

// 	The mount package provides methods to mount marshaled protocol buffers as a filesystem.
package mount

import (
	"fmt"
	"log"
	"strings"
	"os/signal"
	"os"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"

	"github.com/elrichgro/protofuse/unmarshal"
	"github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
)

//	Mounts a marshaled protocol buffer as a filesytem.
func Mount(marshaled []byte, fileDesc *google_protobuf.FileDescriptorSet, packageName string, messageName string, mountPoint string) error {
	// mount
	c, err := fuse.Mount(
		mountPoint,
		fuse.FSName("protofuse"),
		fuse.Subtype("protofs"),
		fuse.LocalVolume(),
		fuse.VolumeName("ProtoFS"),
	)
	if err != nil {
		return err
	}
	defer c.Close()

	// unmount filesystem in the event of an interrupt
	c1 := make(chan os.Signal, 1)
	signal.Notify(c1, os.Interrupt)
	go func(){
    for sig := range c1 {
    	log.Printf("captured %v, unmounting filesystem", sig)
        defer os.Exit(1)
        err = fuse.Unmount(mountPoint)
		if err != nil {
			log.Println(err)
		}
    }
	}()

	// create the filesystem structure
	PT, err := unmarshal.Unmarshal(fileDesc, packageName, messageName, [][]byte{marshaled})
	if err != nil {
		return err
	}

	// serve
	err = fs.Serve(c, PT)
	if err != nil {
		return err
	}
	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; err != nil {
		return err
	}

	return nil
}

// Mounts a list of marshaled protocol buffers as a filesystem.
func MountList(marshaled [][]byte, fileDesc *google_protobuf.FileDescriptorSet, packageName string, messageName string, mountPoint string) error {
	// mount
	c, err := fuse.Mount(
		mountPoint,
		fuse.FSName("protofuse"),
		fuse.Subtype("protofs"),
		fuse.LocalVolume(),
		fuse.VolumeName("ProtoFS"),
	)
	if err != nil {
		return err
	}
	defer c.Close()

	// unmount the filesystem in the event of an interrupt
	c1 := make(chan os.Signal, 1)
	signal.Notify(c1, os.Interrupt)
	go func(){
    for sig := range c1 {
    	log.Printf("captured %v, unmounting filesystem", sig)
        err = fuse.Unmount(mountPoint)
		if err != nil {
			log.Println(err)
		}
    }
	}()

	// create the filesystem structure
	PT, err := unmarshal.Unmarshal(fileDesc, packageName, messageName, marshaled)
	if err != nil {
		return err
	}

	// serve
	err = fs.Serve(c, PT)
	if err != nil {
		return err
	}

	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; err != nil {
		return err
	}

	return nil
}

// Tries to unmount the filesystem at dir.
func Unmount(dir string) error {
	err := fuse.Unmount(dir)
	if err != nil {
		return err
	}
	return nil
}

// Finds the google_protobuf.DescriptorProto for the message name.
func getDescriptorProto(name string, fileDesc *google_protobuf.FileDescriptorSet) (*google_protobuf.DescriptorProto, error) {
	if string(name[0]) == "." {
		s := strings.Split(name, ".")
		slen := len(s)
		for _, file := range fileDesc.File {
			if file.GetPackage() == s[1] {
				for _, message := range file.MessageType {
					if message.GetName() == s[2] {
						if slen <= 3 {
							return message, nil
						}
						var m *google_protobuf.DescriptorProto = message

						for i := 3; i < slen; i++ {
							for _, d := range m.GetNestedType() {
								if d.GetName() == s[i] {
									if i >= slen-1 {
										return d, nil
									}
									m = d
								}
							}
						}
						return nil, fmt.Errorf("Cannot find message1: %s", name)
					}
				}
			}
		}
		return nil, fmt.Errorf("Cannot find message: %s", name)
	}
	return nil, fmt.Errorf("Message name not fully qualified: %s", name)
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2016 Laurent Moussault. All rights reserved.
// Licensed under a simplified BSD license (see LICENSE file).

package mouse

//------------------------------------------------------------------------------

// #cgo windows LDFLAGS: -lSDL2
// #cgo linux freebsd darwin pkg-config: sdl2
// #include "../internal/sdl.h"
import "C"

import (
	"fmt"

	"github.com/drakmaniso/glam/internal"
	"github.com/drakmaniso/glam/pixel"
)

//------------------------------------------------------------------------------

// Handler receives the mouse events.
type Handler interface {
	MouseMotion(motion pixel.Coord, position pixel.Coord, timestamp uint32)
	MouseButtonDown(b Button, clicks int, timestamp uint32)
	MouseButtonUp(b Button, clicks int, timestamp uint32)
	MouseWheel(motion pixel.Coord, timestamp uint32)
}

// Handle is the current handlers for mouse events
//
// It can be changed while the loop is running, but must never be nil.
var Handle Handler

//------------------------------------------------------------------------------

// Position returns the current mouse position, relative to the game window.
// Updated at the start of each game loop iteration.
func Position() pixel.Coord {
	return internal.MousePosition
}

// Delta returns the mouse position relative to the last call of Delta.
func Delta() pixel.Coord {
	result := internal.MouseDelta
	internal.MouseDelta.X, internal.MouseDelta.Y = 0, 0
	return result
}

// SetRelativeMode enables or disables the relative mode, where the mouse is
// hidden and mouse motions are continuously reported.
func SetRelativeMode(enabled bool) error {
	var m C.SDL_bool
	if enabled {
		m = 1
	}
	if C.SDL_SetRelativeMouseMode(m) != 0 {
		return fmt.Errorf("impossible to set relative mouse mode: %s", internal.GetSDLError())
	}
	return nil
}

// GetRelativeMode returns true if the relative mode is enabled.
func GetRelativeMode() bool {
	return C.SDL_GetRelativeMouseMode() == C.SDL_TRUE
}

//------------------------------------------------------------------------------
<commit_msg>Fix cursor hiding in mouse.SetRelativeMode<commit_after>// Copyright (c) 2013-2016 Laurent Moussault. All rights reserved.
// Licensed under a simplified BSD license (see LICENSE file).

package mouse

//------------------------------------------------------------------------------

// #cgo windows LDFLAGS: -lSDL2
// #cgo linux freebsd darwin pkg-config: sdl2
// #include "../internal/sdl.h"
import "C"

import (
	"fmt"

	"github.com/drakmaniso/glam/internal"
	"github.com/drakmaniso/glam/pixel"
)

//------------------------------------------------------------------------------

// Handler receives the mouse events.
type Handler interface {
	MouseMotion(motion pixel.Coord, position pixel.Coord, timestamp uint32)
	MouseButtonDown(b Button, clicks int, timestamp uint32)
	MouseButtonUp(b Button, clicks int, timestamp uint32)
	MouseWheel(motion pixel.Coord, timestamp uint32)
}

// Handle is the current handlers for mouse events
//
// It can be changed while the loop is running, but must never be nil.
var Handle Handler

//------------------------------------------------------------------------------

// Position returns the current mouse position, relative to the game window.
// Updated at the start of each game loop iteration.
func Position() pixel.Coord {
	return internal.MousePosition
}

// Delta returns the mouse position relative to the last call of Delta.
func Delta() pixel.Coord {
	result := internal.MouseDelta
	internal.MouseDelta.X, internal.MouseDelta.Y = 0, 0
	return result
}

// SetRelativeMode enables or disables the relative mode, where the mouse is
// hidden and mouse motions are continuously reported.
func SetRelativeMode(enabled bool) error {
	var m C.SDL_bool
	if enabled {
		m = 1
		C.SDL_ShowCursor(C.SDL_DISABLE)
	}
	if C.SDL_SetRelativeMouseMode(m) != 0 {
		C.SDL_ShowCursor(C.SDL_ENABLE)
		return fmt.Errorf("impossible to set relative mouse mode: %s", internal.GetSDLError())
	}
	C.SDL_ShowCursor(C.SDL_ENABLE)
	return nil
}

// GetRelativeMode returns true if the relative mode is enabled.
func GetRelativeMode() bool {
	return C.SDL_GetRelativeMouseMode() == C.SDL_TRUE
}

//------------------------------------------------------------------------------
<|endoftext|>


<commit_before>package handlers

import (
	"crypto/rand"
	"encoding/hex"
	"flag"
	"fmt"
	"github.com/FactomProject/cli"
	"github.com/FactomProject/serveridentity/functions"
	"github.com/FactomProject/serveridentity/identity"
	"io"
	"os"
)

var SCRIPTNAME string = "fullidentity"
var PRINT_OUT bool = true

/*
 * This file is only used for testing purposes
 */

var Full = func() *sevCmd {
	identity.ShowBruteForce = PRINT_OUT
	cmd := new(sevCmd)
	cmd.helpMsg = "serveridentity full 'fresh'|ESAddress"
	cmd.description = "Create new identity and subchain as well as entries in the subchain."
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		c := cli.New()
		c.HandleFunc("fresh", freshFull)
		c.HandleDefaultFunc(existingECFull)
		c.HandleFunc("help", func(args []string) {
			fmt.Println(cmd.helpMsg)
		})
		c.Execute(args)
	}
	Help.Add("Create a full Identity", cmd)
	return cmd
}()

func existingECFull(args []string) {
	if len(args) == 0 {
		Help.All()
		return
	}
	os.Args = args
	filename := flag.String("n", "fullidentity", "Change the script name")
	garble := flag.Bool("b", false, "Make incorrect entries")
	flag.Parse()
	SCRIPTNAME = *filename
	l := len(args[0])
	if l != 64 && l != 52 {
		fmt.Println("server identity full 'fresh'|ESAddress")
		fmt.Println("Invalid ES Address entered, exiting program...")
		return
	} else if l == 52 {
		// Generate all new Keys from EC
		sid := generateKeysFromEC(args[0], PRINT_OUT)
		if sid == nil {
			return
		}
		fullStart(sid, *garble)
	} else if l == 64 {
		fmt.Println("Only base58 human readable key accepted.")
	}
}

func freshFull(args []string) {
	os.Args = args
	filename := flag.String("n", "fullidentity", "Change the script name")
	garble := flag.Bool("b", false, "Make incorrect entries")
	flag.Parse()
	SCRIPTNAME = *filename
	// Generate all new Keys
	sid := generateKeys(PRINT_OUT)
	if sid == nil {
		return
	}
	fullStart(sid, *garble)
}

func fullStart(sid *functions.ServerIdentity, garble bool) {
	if garble {
		fmt.Println("Incorrect curls also provided")
	}
	file = makeFile(SCRIPTNAME)
	defer file.Close()
	var bar string
	for i := 0; i < 76; i++ {
		bar = bar + "\\*"
	}
	if PRINT_OUT {
		PrintHeader("Root Chain Curls")
	}
	createIdentityChain(sid, PRINT_OUT)
	registerIdentityChain(sid, PRINT_OUT)
	if PRINT_OUT {
		PrintHeader("Sub Chain Curls")
	}
	createSubChain(sid, PRINT_OUT)
	registerSubChain(sid, PRINT_OUT)

	random := rand.Reader
	var r [20]byte
	_, _ = io.ReadFull(random, r[:20])
	btcKeyHex := r[:20]

	p := sid.IDSet.IdentityLevel[0].GetPrivateKey()
	priv := p[:32]

	file.WriteString("sleep 1\n")

	strCom, strRev, err := functions.CreateNewBitcoinKey(sid.RootChainID, sid.SubChainID, 0, 0, btcKeyHex, priv, sid.ECAddr)
	if err != nil {
		panic(err)
	}
	writeCurlCmd(file, "New Bitcoin Key", strCom, strRev)

	strCom, strRev, newPriv, err := functions.CreateNewBlockSignEntry(sid.RootChainID, sid.SubChainID, priv, sid.ECAddr)
	if err != nil {
		panic(err)
	}
	writeCurlCmd(file, "New Block Signing Key", strCom, strRev)

	strCom, strRev, mHash, err := functions.CreateNewMHash(sid.RootChainID, sid.SubChainID, priv, sid.RootChainID, sid.ECAddr)
	if err != nil {
		panic(err)
	}
	writeCurlCmd(file, "New Matryoshka Hash", strCom, strRev)

	file.WriteString("echo " + bar + "\n")
	file.WriteString("echo  Identity Info\n")
	file.WriteString("echo " + bar + "\n")
	file.WriteString("echo  Identity Chain: " + sid.RootChainID + "\n")
	file.WriteString("echo  Identity SubChain: " + sid.SubChainID + "\n")

	file.WriteString("echo EC Public : " + sid.ECAddr.PubString() + "\n")
	file.WriteString("echo EC Private: " + sid.ECAddr.SecString() + "\n")
	file.WriteString("echo  \n")
	file.WriteString("echo  Private Keys\n")
	for i, r := range sid.IDSet.IdentityLevel {
		file.WriteString(fmt.Sprintf("echo  Level %d: %s\n", i+1, r.HumanReadablePrivate()))
	}
	file.WriteString("echo  \n")
	file.WriteString("echo  BTC Key: " + hex.EncodeToString(btcKeyHex) + "\n")
	keyString := hex.EncodeToString(newPriv)
	keyString = "\n echo - Sec: " + keyString[:64] + "\n echo - Pub: " + keyString[65:]
	file.WriteString("echo  Block Signing Key: " + keyString + "\n")
	file.WriteString("echo  \n")
	file.WriteString("echo  MHashSeed: " + sid.RootChainID + "\n")
	file.WriteString("echo  MHash: " + mHash + "\n")

	if garble {
		PrintHeader("GARBLE: Wrong Key")
		p = sid.IDSet.IdentityLevel[2].GetPrivateKey()
		priv = p[:32]

		file.WriteString("sleep 1\n")

		strCom, strRev, err = functions.CreateNewBitcoinKey(sid.RootChainID, sid.SubChainID, 0, 0, btcKeyHex, priv, sid.ECAddr)
		if err != nil {
			//panic(err)
		}
		writeCurlCmd(file, "New Bitcoin Key", strCom, strRev)

		strCom, strRev, newPriv, err = functions.CreateNewBlockSignEntry(sid.RootChainID, sid.SubChainID, priv, sid.ECAddr)
		if err != nil {
			//panic(err)
		}
		writeCurlCmd(file, "New Block Signing Key", strCom, strRev)

		strCom, strRev, mhash, err := functions.CreateNewMHash(sid.RootChainID, sid.SubChainID, priv, sid.RootChainID, sid.ECAddr)
		if err != nil {
			//panic(err)
		}
		writeCurlCmd(file, "New Matryoshka Hash", strCom, strRev)

		PrintHeader("GARBLE: Bad Key & BTC KEY")
		btcKeyHex = []byte{0x00, 0x00, 0x00}
		p = sid.IDSet.IdentityLevel[0].GetPrivateKey()
		priv = p[1:33]

		file.WriteString("sleep 1\n")

		strCom, strRev, err = functions.CreateNewBitcoinKey(sid.RootChainID, sid.SubChainID, 0, 0, btcKeyHex, priv, sid.ECAddr)
		if err != nil {
			//panic(err)
		}
		writeCurlCmd(file, "New Bitcoin Key", strCom, strRev)

		strCom, strRev, newPriv, err = functions.CreateNewBlockSignEntry(sid.RootChainID, sid.SubChainID, priv, sid.ECAddr)
		if err != nil {
			//panic(err)
		}
		writeCurlCmd(file, "New Block Signing Key", strCom, strRev)

		strCom, strRev, mhash, err = functions.CreateNewMHash(sid.RootChainID, sid.SubChainID, priv, sid.RootChainID, sid.ECAddr)
		if err != nil {
			//panic(err)
		}
		writeCurlCmd(file, "New Matryoshka Hash", strCom, strRev)
		file.WriteString("echo  \n")
		file.WriteString("echo  BTC Key: " + hex.EncodeToString(btcKeyHex) + "\n")
		file.WriteString("echo  Block Signing Key: " + hex.EncodeToString(newPriv) + "\n")
		file.WriteString("echo  MHash: " + mhash + "\n")
	}

}
<commit_msg>Missed 1 byte in display<commit_after>package handlers

import (
	"crypto/rand"
	"encoding/hex"
	"flag"
	"fmt"
	"github.com/FactomProject/cli"
	"github.com/FactomProject/serveridentity/functions"
	"github.com/FactomProject/serveridentity/identity"
	"io"
	"os"
)

var SCRIPTNAME string = "fullidentity"
var PRINT_OUT bool = true

/*
 * This file is only used for testing purposes
 */

var Full = func() *sevCmd {
	identity.ShowBruteForce = PRINT_OUT
	cmd := new(sevCmd)
	cmd.helpMsg = "serveridentity full 'fresh'|ESAddress"
	cmd.description = "Create new identity and subchain as well as entries in the subchain."
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		c := cli.New()
		c.HandleFunc("fresh", freshFull)
		c.HandleDefaultFunc(existingECFull)
		c.HandleFunc("help", func(args []string) {
			fmt.Println(cmd.helpMsg)
		})
		c.Execute(args)
	}
	Help.Add("Create a full Identity", cmd)
	return cmd
}()

func existingECFull(args []string) {
	if len(args) == 0 {
		Help.All()
		return
	}
	os.Args = args
	filename := flag.String("n", "fullidentity", "Change the script name")
	garble := flag.Bool("b", false, "Make incorrect entries")
	flag.Parse()
	SCRIPTNAME = *filename
	l := len(args[0])
	if l != 64 && l != 52 {
		fmt.Println("server identity full 'fresh'|ESAddress")
		fmt.Println("Invalid ES Address entered, exiting program...")
		return
	} else if l == 52 {
		// Generate all new Keys from EC
		sid := generateKeysFromEC(args[0], PRINT_OUT)
		if sid == nil {
			return
		}
		fullStart(sid, *garble)
	} else if l == 64 {
		fmt.Println("Only base58 human readable key accepted.")
	}
}

func freshFull(args []string) {
	os.Args = args
	filename := flag.String("n", "fullidentity", "Change the script name")
	garble := flag.Bool("b", false, "Make incorrect entries")
	flag.Parse()
	SCRIPTNAME = *filename
	// Generate all new Keys
	sid := generateKeys(PRINT_OUT)
	if sid == nil {
		return
	}
	fullStart(sid, *garble)
}

func fullStart(sid *functions.ServerIdentity, garble bool) {
	if garble {
		fmt.Println("Incorrect curls also provided")
	}
	file = makeFile(SCRIPTNAME)
	defer file.Close()
	var bar string
	for i := 0; i < 76; i++ {
		bar = bar + "\\*"
	}
	if PRINT_OUT {
		PrintHeader("Root Chain Curls")
	}
	createIdentityChain(sid, PRINT_OUT)
	registerIdentityChain(sid, PRINT_OUT)
	if PRINT_OUT {
		PrintHeader("Sub Chain Curls")
	}
	createSubChain(sid, PRINT_OUT)
	registerSubChain(sid, PRINT_OUT)

	random := rand.Reader
	var r [20]byte
	_, _ = io.ReadFull(random, r[:20])
	btcKeyHex := r[:20]

	p := sid.IDSet.IdentityLevel[0].GetPrivateKey()
	priv := p[:32]

	file.WriteString("sleep 1\n")

	strCom, strRev, err := functions.CreateNewBitcoinKey(sid.RootChainID, sid.SubChainID, 0, 0, btcKeyHex, priv, sid.ECAddr)
	if err != nil {
		panic(err)
	}
	writeCurlCmd(file, "New Bitcoin Key", strCom, strRev)

	strCom, strRev, newPriv, err := functions.CreateNewBlockSignEntry(sid.RootChainID, sid.SubChainID, priv, sid.ECAddr)
	if err != nil {
		panic(err)
	}
	writeCurlCmd(file, "New Block Signing Key", strCom, strRev)

	strCom, strRev, mHash, err := functions.CreateNewMHash(sid.RootChainID, sid.SubChainID, priv, sid.RootChainID, sid.ECAddr)
	if err != nil {
		panic(err)
	}
	writeCurlCmd(file, "New Matryoshka Hash", strCom, strRev)

	file.WriteString("echo " + bar + "\n")
	file.WriteString("echo  Identity Info\n")
	file.WriteString("echo " + bar + "\n")
	file.WriteString("echo  Identity Chain: " + sid.RootChainID + "\n")
	file.WriteString("echo  Identity SubChain: " + sid.SubChainID + "\n")

	file.WriteString("echo EC Public : " + sid.ECAddr.PubString() + "\n")
	file.WriteString("echo EC Private: " + sid.ECAddr.SecString() + "\n")
	file.WriteString("echo  \n")
	file.WriteString("echo  Private Keys\n")
	for i, r := range sid.IDSet.IdentityLevel {
		file.WriteString(fmt.Sprintf("echo  Level %d: %s\n", i+1, r.HumanReadablePrivate()))
	}
	file.WriteString("echo  \n")
	file.WriteString("echo  BTC Key: " + hex.EncodeToString(btcKeyHex) + "\n")
	keyString := hex.EncodeToString(newPriv)
	keyString = "\n echo - Sec: " + keyString[:64] + "\n echo - Pub: " + keyString[64:]
	file.WriteString("echo  Block Signing Key: " + keyString + "\n")
	file.WriteString("echo  \n")
	file.WriteString("echo  MHashSeed: " + sid.RootChainID + "\n")
	file.WriteString("echo  MHash: " + mHash + "\n")

	if garble {
		PrintHeader("GARBLE: Wrong Key")
		p = sid.IDSet.IdentityLevel[2].GetPrivateKey()
		priv = p[:32]

		file.WriteString("sleep 1\n")

		strCom, strRev, err = functions.CreateNewBitcoinKey(sid.RootChainID, sid.SubChainID, 0, 0, btcKeyHex, priv, sid.ECAddr)
		if err != nil {
			//panic(err)
		}
		writeCurlCmd(file, "New Bitcoin Key", strCom, strRev)

		strCom, strRev, newPriv, err = functions.CreateNewBlockSignEntry(sid.RootChainID, sid.SubChainID, priv, sid.ECAddr)
		if err != nil {
			//panic(err)
		}
		writeCurlCmd(file, "New Block Signing Key", strCom, strRev)

		strCom, strRev, mhash, err := functions.CreateNewMHash(sid.RootChainID, sid.SubChainID, priv, sid.RootChainID, sid.ECAddr)
		if err != nil {
			//panic(err)
		}
		writeCurlCmd(file, "New Matryoshka Hash", strCom, strRev)

		PrintHeader("GARBLE: Bad Key & BTC KEY")
		btcKeyHex = []byte{0x00, 0x00, 0x00}
		p = sid.IDSet.IdentityLevel[0].GetPrivateKey()
		priv = p[1:33]

		file.WriteString("sleep 1\n")

		strCom, strRev, err = functions.CreateNewBitcoinKey(sid.RootChainID, sid.SubChainID, 0, 0, btcKeyHex, priv, sid.ECAddr)
		if err != nil {
			//panic(err)
		}
		writeCurlCmd(file, "New Bitcoin Key", strCom, strRev)

		strCom, strRev, newPriv, err = functions.CreateNewBlockSignEntry(sid.RootChainID, sid.SubChainID, priv, sid.ECAddr)
		if err != nil {
			//panic(err)
		}
		writeCurlCmd(file, "New Block Signing Key", strCom, strRev)

		strCom, strRev, mhash, err = functions.CreateNewMHash(sid.RootChainID, sid.SubChainID, priv, sid.RootChainID, sid.ECAddr)
		if err != nil {
			//panic(err)
		}
		writeCurlCmd(file, "New Matryoshka Hash", strCom, strRev)
		file.WriteString("echo  \n")
		file.WriteString("echo  BTC Key: " + hex.EncodeToString(btcKeyHex) + "\n")
		file.WriteString("echo  Block Signing Key: " + hex.EncodeToString(newPriv) + "\n")
		file.WriteString("echo  MHash: " + mhash + "\n")
	}

}
<|endoftext|>


<commit_before>package mstate

import (
	"errors"
	"fmt"
	"labix.org/v2/mgo/bson"
)

// unitDoc represents the internal state of a unit in MongoDB.
type unitDoc struct {
	Name      string `bson:"_id"`
	Service   string
	Principal string
	MachineId *int
	Life      Life
}

// Unit represents the state of a service unit.
type Unit struct {
	st  *State
	doc unitDoc
}

func newUnit(st *State, udoc *unitDoc) *Unit {
	return &Unit{
		st:  st,
		doc: *udoc,
	}
}

// ServiceName returns the service name.
func (u *Unit) ServiceName() string {
	return u.doc.Service
}

// String returns the unit as string.
func (u *Unit) String() string {
	return u.doc.Name
}

// Name returns the unit name.
func (u *Unit) Name() string {
	return u.doc.Name
}

// IsPrincipal returns whether the unit is deployed in its own container,
// and can therefore have subordinate services deployed alongside it.
func (u *Unit) IsPrincipal() bool {
	return u.doc.Principal == ""
}

func (u *Unit) Refresh() error {
	err := u.st.units.FindId(u.doc.Name).One(&u.doc)
	if err != nil {
		return fmt.Errorf("cannot refresh unit %v: %v", u, err)
	}
	return nil
}

// AssignedMachineId returns the id of the assigned machine.
func (u *Unit) AssignedMachineId() (id int, err error) {
	defer errorContextf(&err, "cannot get machine id of unit %q", u)
	if u.IsPrincipal() {
		if u.doc.MachineId == nil {
			return 0, errors.New("unit not assigned to machine")
		}
		return *u.doc.MachineId, nil
	}
	pudoc := unitDoc{}
	sel := bson.D{{"_id", u.doc.Principal}, {"life", Alive}}
	err = u.st.units.Find(sel).One(&pudoc)
	if err != nil {
		return 0, err
	}
	if pudoc.MachineId == nil {
		return 0, errors.New("unit not assigned to machine")
	}
	return *pudoc.MachineId, nil
}

// AssignToMachine assigns this unit to a given machine.
func (u *Unit) AssignToMachine(m *Machine) (err error) {
	change := bson.D{{"$set", bson.D{{"machineid", m.Id()}}}}
	sel := bson.D{
		{"_id", u.doc.Name},
		{"$or", []bson.D{
			bson.D{{"machineid", nil}},
			bson.D{{"machineid", m.Id()}},
		}},
	}
	err = u.st.units.Update(sel, change)
	if err != nil {
		return fmt.Errorf("cannot assign unit %q to machine %s: %v", u, m, err)
	}
	u.doc.MachineId = &m.doc.Id
	return nil
}

// UnassignFromMachine removes the assignment between this unit and the
// machine it's assigned to.
func (u *Unit) UnassignFromMachine() (err error) {
	change := bson.D{{"$set", bson.D{{"machineid", nil}}}}
	sel := bson.D{{"_id", u.doc.Name}}
	err = u.st.units.Update(sel, change)
	if err != nil {
		return fmt.Errorf("cannot unassign unit %q from machine: %v", u, err)
	}
	return nil
}
<commit_msg>mstate: address review points<commit_after>package mstate

import (
	"errors"
	"fmt"
	"labix.org/v2/mgo/bson"
)

// unitDoc represents the internal state of a unit in MongoDB.
type unitDoc struct {
	Name      string `bson:"_id"`
	Service   string
	Principal string
	MachineId *int
	Life      Life
}

// Unit represents the state of a service unit.
type Unit struct {
	st  *State
	doc unitDoc
}

func newUnit(st *State, udoc *unitDoc) *Unit {
	return &Unit{
		st:  st,
		doc: *udoc,
	}
}

// ServiceName returns the service name.
func (u *Unit) ServiceName() string {
	return u.doc.Service
}

// String returns the unit as string.
func (u *Unit) String() string {
	return u.doc.Name
}

// Name returns the unit name.
func (u *Unit) Name() string {
	return u.doc.Name
}

// IsPrincipal returns whether the unit is deployed in its own container,
// and can therefore have subordinate services deployed alongside it.
func (u *Unit) IsPrincipal() bool {
	return u.doc.Principal == ""
}

func (u *Unit) Refresh() error {
	err := u.st.units.FindId(u.doc.Name).One(&u.doc)
	if err != nil {
		return fmt.Errorf("cannot refresh unit %q: %v", u, err)
	}
	return nil
}

// AssignedMachineId returns the id of the assigned machine.
func (u *Unit) AssignedMachineId() (id int, err error) {
	defer errorContextf(&err, "cannot get machine id of unit %q", u)
	if u.IsPrincipal() {
		if u.doc.MachineId == nil {
			return 0, errors.New("unit not assigned to machine")
		}
		return *u.doc.MachineId, nil
	}
	pudoc := unitDoc{}
	sel := bson.D{{"_id", u.doc.Principal}, {"life", Alive}}
	err = u.st.units.Find(sel).One(&pudoc)
	if err != nil {
		return 0, err
	}
	if pudoc.MachineId == nil {
		return 0, errors.New("unit not assigned to machine")
	}
	return *pudoc.MachineId, nil
}

// AssignToMachine assigns this unit to a given machine.
func (u *Unit) AssignToMachine(m *Machine) (err error) {
	change := bson.D{{"$set", bson.D{{"machineid", m.Id()}}}}
	sel := bson.D{
		{"_id", u.doc.Name},
		{"$or", []bson.D{
			bson.D{{"machineid", nil}},
			bson.D{{"machineid", m.Id()}},
		}},
	}
	err = u.st.units.Update(sel, change)
	if err != nil {
		return fmt.Errorf("cannot assign unit %q to machine %s: %v", u, m, err)
	}
	u.doc.MachineId = &m.doc.Id
	return nil
}

// UnassignFromMachine removes the assignment between this unit and the
// machine it's assigned to.
func (u *Unit) UnassignFromMachine() (err error) {
	change := bson.D{{"$set", bson.D{{"machineid", nil}}}}
	sel := bson.D{{"_id", u.doc.Name}}
	err = u.st.units.Update(sel, change)
	if err != nil {
		return fmt.Errorf("cannot unassign unit %q from machine: %v", u, err)
	}
	return nil
}
<|endoftext|>