<commit_before>package logging

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path"
	"runtime"
	"strconv"
	"strings"
	"time"
)

// L is the global Logger instance.
var L *Logger

func init() {
	L = New("")
}

// New creates a new private Logger. If fileName is an empty string, the Logger will write to stdout. New will return nil if it can't create/open fileName.
func New(fileName string) *Logger {
	hostname, _ := os.Hostname()
	l := Logger{
		appName:    path.Base(os.Args[0]),
		hostName:   hostname,
		pid:        strconv.Itoa(os.Getpid()),
		doDebug:    false,
		doInfo:     true,
		doWarning:  true,
		doError:    true,
		doCritical: true,
		doFatal:    true,
	}
	err := l.SetLogFile(fileName)
	if err != nil {
		return nil
	}
	return &l
}

// Logger is a type passed to the logging functions. It stores the log settings.
type Logger struct {
	appName     string
	hostName    string
	pid         string
	jsonWriter  io.WriteCloser
	textWriter  io.WriteCloser
	jsonChannel chan<- string
	doDebug     bool
	doInfo      bool
	doWarning   bool
	doError     bool
	doCritical  bool
	doFatal     bool
}

// SetLogFile sets fileName as the log file target. An empty string sets text file logging to stdout
// and json logging to null (ie, no json output); this is the default.
// Normally, there are two log files, one for text and one for json. The text file will be written to
// filename, while the json content will be written to filename.json
// If filename.json cannot be opened for write (eg, filename = "/dev/null"), then
// both text and json will be written to filename.
func (l *Logger) SetLogFile(fileName string) error {
	var textWriter, jsonWriter *os.File
	var err error
	if len(fileName) == 0 {
		textWriter = os.Stdout
		jsonWriter, _ = os.OpenFile("/dev/null", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
	} else {
		textWriter, err = os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
		if err == nil {
			jsonWriter, err = os.OpenFile(fmt.Sprintf("%s.json", fileName), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
			if err != nil {
				jsonWriter = textWriter
				err = nil
			}
		}
	}
	if err == nil {
		if l.textWriter != nil && l.textWriter != os.Stdout {
			l.textWriter.Close()
		}
		if l.jsonWriter != nil && l.jsonWriter != os.Stdout && l.jsonWriter != l.textWriter {
			l.jsonWriter.Close()
		}
		l.textWriter = textWriter
		l.jsonWriter = jsonWriter
	}
	return err
}

// WriteJSONToChannel changes the destination of the json entries from a local file to a channel. Note that
// SetLogFile will change it back to using a local file, so keep the call order in mind.
func (l *Logger) WriteJSONToChannel(c chan<- string) {
	l.jsonChannel = c
}

// SetOutput controls which levels of logging are enabled/disabled
func (l *Logger) SetOutput(debug, info, warning, err, critical, fatal bool) {
	l.doDebug = debug
	l.doInfo = info
	l.doWarning = warning
	l.doError = err
	l.doCritical = critical
	l.doFatal = fatal
}

// Error is like Debug for ERROR log entries.
func (l *Logger) Error(values map[string]string, format string, args ...interface{}) error {
	if !l.doError {
		return nil
	}
	return l.writeEntry("ERROR", values, format, args...)
}

// Warning is like Debug for WARNING log entries.
func (l *Logger) Warning(values map[string]string, format string, args ...interface{}) error {
	if !l.doWarning {
		return nil
	}
	return l.writeEntry("WARNING", values, format, args...)
}

// Info is like Debug for INFO log entries.
func (l *Logger) Info(values map[string]string, format string, args ...interface{}) error {
	if !l.doInfo {
		return nil
	}
	return l.writeEntry("INFO", values, format, args...)
}

// Debug writes a DEBUG log entry. The optional values map contains
// user-supplied key-value pairs. format and args are passed to fmt.Printf
// to generate the message entry.
func (l *Logger) Debug(values map[string]string, format string, args ...interface{}) error {
	if !l.doDebug {
		return nil
	}
	return l.writeEntry("DEBUG", values, format, args...)
}

// Critical is like Debug for CRITICAL log entries.
func (l *Logger) Critical(values map[string]string, format string, args ...interface{}) error {
	if !l.doCritical {
		return nil
	}
	return l.writeEntry("CRITICAL", values, format, args...)
}

// Fatal is like Debug for FATAL log entries, but it also calls os.Exit(1).
func (l *Logger) Fatal(values map[string]string, format string, args ...interface{}) error {
	if !l.doFatal {
		return nil
	}
	err := l.writeEntry("FATAL", values, format, args...)
	os.Exit(1)
	return err // won't actually get here
}

func (l *Logger) writeEntry(severity string, values map[string]string, format string, args ...interface{}) error {
	kv := l.getHeaderValues(severity)
	headerStr := makeHeaderString(kv)
	messageStr := fmt.Sprintf(format, args...)
	if strings.ContainsAny(messageStr, "{}\t") {
		messageStr = strings.Replace(messageStr, "\t", " ", -1)
		messageStr = strings.Replace(messageStr, "{", "[", -1)
		messageStr = strings.Replace(messageStr, "}", "]", -1)
	}
	_, err := fmt.Fprintf(l.textWriter, "%s\t%s\n", headerStr, messageStr)
	if err != nil {
		return err
	}
	jsonStr, err := makeJSONString(kv, values, messageStr)
	if err != nil {
		return err
	}
	if l.jsonChannel != nil {
		l.jsonChannel <- jsonStr
	} else {
		_, err = fmt.Fprintln(l.jsonWriter, jsonStr)
	}
	return err
}

func (l *Logger) getHeaderValues(severity string) map[string]string {
	pc, file, line, _ := runtime.Caller(3)
	f := runtime.FuncForPC(pc)
	caller := f.Name()
	m := map[string]string{
		"timestamp": time.Now().UTC().Format(time.RFC3339Nano),
		"severity":  severity,
		"pid":       l.pid,
		"app":       l.appName,
		"host":      l.hostName,
		"line":      strconv.Itoa(line),
		"file":      path.Base(file),
		"function":  path.Base(caller),
	}
	return m
}

func makeHeaderString(m map[string]string) string {
	return strings.Join([]string{m["timestamp"], m["severity"]}, "\t")
}

func makeJSONString(header map[string]string, kv map[string]string, message string) (string, error) {
	merged := make(map[string]string)
	for k, v := range kv {
		merged[k] = v
	}
	for k, v := range header {
		merged[k] = v
	}
	merged["message"] = message
	b, err := json.Marshal(merged)
	if err != nil {
		return "", err
	}
	return string(b), nil
}
<commit_msg>add ALERT logging level and add a convenience method to enable all logging levels<commit_after>package logging

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path"
	"runtime"
	"strconv"
	"strings"
	"time"
)

// L is the global Logger instance.
var L *Logger

func init() {
	L = New("")
}

// New creates a new private Logger. If fileName is an empty string, the Logger will write to stdout. New will return nil if it can't create/open fileName.
func New(fileName string) *Logger {
	hostname, _ := os.Hostname()
	l := Logger{
		appName:    path.Base(os.Args[0]),
		hostName:   hostname,
		pid:        strconv.Itoa(os.Getpid()),
		doDebug:    false,
		doInfo:     true,
		doWarning:  true,
		doError:    true,
		doCritical: true,
		doFatal:    true,
	}
	err := l.SetLogFile(fileName)
	if err != nil {
		return nil
	}
	return &l
}

// Logger is a type passed to the logging functions. It stores the log settings.
type Logger struct {
	appName     string
	hostName    string
	pid         string
	jsonWriter  io.WriteCloser
	textWriter  io.WriteCloser
	jsonChannel chan<- string
	doDebug     bool
	doInfo      bool
	doWarning   bool
	doError     bool
	doCritical  bool
	doFatal     bool
}

// SetLogFile sets fileName as the log file target. An empty string sets text file logging to stdout
// and json logging to null (ie, no json output); this is the default.
// Normally, there are two log files, one for text and one for json. The text file will be written to
// filename, while the json content will be written to filename.json
// If filename.json cannot be opened for write (eg, filename = "/dev/null"), then
// both text and json will be written to filename.
func (l *Logger) SetLogFile(fileName string) error {
	var textWriter, jsonWriter *os.File
	var err error
	if len(fileName) == 0 {
		textWriter = os.Stdout
		jsonWriter, _ = os.OpenFile("/dev/null", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
	} else {
		textWriter, err = os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
		if err == nil {
			jsonWriter, err = os.OpenFile(fmt.Sprintf("%s.json", fileName), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
			if err != nil {
				jsonWriter = textWriter
				err = nil
			}
		}
	}
	if err == nil {
		if l.textWriter != nil && l.textWriter != os.Stdout {
			l.textWriter.Close()
		}
		if l.jsonWriter != nil && l.jsonWriter != os.Stdout && l.jsonWriter != l.textWriter {
			l.jsonWriter.Close()
		}
		l.textWriter = textWriter
		l.jsonWriter = jsonWriter
	}
	return err
}

// WriteJSONToChannel changes the destination of the json entries from a local file to a channel. Note that
// SetLogFile will change it back to using a local file, so keep the call order in mind.
func (l *Logger) WriteJSONToChannel(c chan<- string) {
	l.jsonChannel = c
}

// SetOutput controls which levels of logging are enabled/disabled
func (l *Logger) SetOutput(debug, info, warning, err, critical, fatal bool) {
	l.doDebug = debug
	l.doInfo = info
	l.doWarning = warning
	l.doError = err
	l.doCritical = critical
	l.doFatal = fatal
}

// EnableAllOutput is the same as SetOutput(true, true, true, true, true, true) and is
// a convenience function that may be useful for easily enabling logging during tests.
func (l *Logger) EnableAllOutput() {
	l.doDebug = true
	l.doInfo = true
	l.doWarning = true
	l.doError = true
	l.doCritical = true
	l.doFatal = true
}

// Error is like Debug for ERROR log entries.
func (l *Logger) Error(values map[string]string, format string, args ...interface{}) error {
	if !l.doError {
		return nil
	}
	return l.writeEntry("ERROR", values, format, args...)
}

// Warning is like Debug for WARNING log entries.
func (l *Logger) Warning(values map[string]string, format string, args ...interface{}) error {
	if !l.doWarning {
		return nil
	}
	return l.writeEntry("WARNING", values, format, args...)
}

// Info is like Debug for INFO log entries.
func (l *Logger) Info(values map[string]string, format string, args ...interface{}) error {
	if !l.doInfo {
		return nil
	}
	return l.writeEntry("INFO", values, format, args...)
}

// Debug writes a DEBUG log entry. The optional values map contains
// user-supplied key-value pairs. format and args are passed to fmt.Printf
// to generate the message entry.
func (l *Logger) Debug(values map[string]string, format string, args ...interface{}) error {
	if !l.doDebug {
		return nil
	}
	return l.writeEntry("DEBUG", values, format, args...)
}

// Critical is like Debug for CRITICAL log entries.
func (l *Logger) Critical(values map[string]string, format string, args ...interface{}) error {
	if !l.doCritical {
		return nil
	}
	return l.writeEntry("CRITICAL", values, format, args...)
}

// Fatal is like Debug for FATAL log entries, but it also calls os.Exit(1).
func (l *Logger) Fatal(values map[string]string, format string, args ...interface{}) error {
	if !l.doFatal {
		return nil
	}
	err := l.writeEntry("FATAL", values, format, args...)
	os.Exit(1)
	return err // won't actually get here
}

func (l *Logger) writeEntry(severity string, values map[string]string, format string, args ...interface{}) error {
	kv := l.getHeaderValues(severity)
	headerStr := makeHeaderString(kv)
	messageStr := fmt.Sprintf(format, args...)
	if strings.ContainsAny(messageStr, "{}\t") {
		messageStr = strings.Replace(messageStr, "\t", " ", -1)
		messageStr = strings.Replace(messageStr, "{", "[", -1)
		messageStr = strings.Replace(messageStr, "}", "]", -1)
	}
	_, err := fmt.Fprintf(l.textWriter, "%s\t%s\n", headerStr, messageStr)
	if err != nil {
		return err
	}
	jsonStr, err := makeJSONString(kv, values, messageStr)
	if err != nil {
		return err
	}
	if l.jsonChannel != nil {
		l.jsonChannel <- jsonStr
	} else {
		_, err = fmt.Fprintln(l.jsonWriter, jsonStr)
	}
	return err
}

func (l *Logger) getHeaderValues(severity string) map[string]string {
	pc, file, line, _ := runtime.Caller(3)
	f := runtime.FuncForPC(pc)
	caller := f.Name()
	m := map[string]string{
		"timestamp": time.Now().UTC().Format(time.RFC3339Nano),
		"severity":  severity,
		"pid":       l.pid,
		"app":       l.appName,
		"host":      l.hostName,
		"line":      strconv.Itoa(line),
		"file":      path.Base(file),
		"function":  path.Base(caller),
	}
	return m
}

func makeHeaderString(m map[string]string) string {
	return strings.Join([]string{m["timestamp"], m["severity"]}, "\t")
}

func makeJSONString(header map[string]string, kv map[string]string, message string) (string, error) {
	merged := make(map[string]string)
	for k, v := range kv {
		merged[k] = v
	}
	for k, v := range header {
		merged[k] = v
	}
	merged["message"] = message
	b, err := json.Marshal(merged)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

type AlertLevel int

const (
	OK AlertLevel = iota
	WARNING
	CRITICAL
)

func (a AlertLevel) String() string {
	switch a {
	case OK:
		return "OK"
	case WARNING:
		return "WARNING"
	case CRITICAL:
		return "CRTICIAL"
	}
	return fmt.Sprintf("UNKNOWN_%d", int(a))
}

// Alert is somewhat special: it can not be disabled, and it creates more automatic header values.
func (l *Logger) Alert(level AlertLevel, format string, args ...interface{}) error {
	values := make(map[string]string)
	values["alert_level"] = level.String()
	return l.writeEntry("ALERT", values, format, args...)
}
<|endoftext|>


<commit_before>package alpaca

import (
	"bitbucket.org/pkg/inflect"
	"errors"
)

func WritePhp(data *Data) {
	MakeLibraryDir("php")
	RunTemplate := ChooseTemplate("php")

	RunTemplate("gitignore", ".gitignore", data)
	RunTemplate("composer.json", "composer.json", data)
	RunTemplate("readme.md", "README.md", data)

	MakeDir("lib")

	MakeDir(inflect.Camelize(data.Pkg.Name))
	RunTemplate("lib/Client.php", "Client.php", data)

	MakeDir("Exception")
	RunTemplate("lib/Exception/ExceptionInterface.php", "ExceptionInterface.php", data)
	RunTemplate("lib/Exception/ClientException.php", "ClientException.php", data)
	MoveDir("..")

	MakeDir("HttpClient")
	RunTemplate("lib/HttpClient/HttpClient.php", "HttpClient.php", data)
	RunTemplate("lib/HttpClient/AuthHandler.php", "AuthHandler.php", data)
	RunTemplate("lib/HttpClient/ErrorHandler.php", "ErrorHandler.php", data)
	RunTemplate("lib/HttpClient/RequestHandler.php", "RequestHandler.php", data)
	RunTemplate("lib/HttpClient/Response.php", "Response.php", data)
	RunTemplate("lib/HttpClient/ResponseHandler.php", "ResponseHandler.php", data)
	MoveDir("..")

	MakeDir("Api")

	for k, v := range data.Api["class"].(map[string]interface{}) {
		data.Api["active"] = ActiveClassInfo(k, v)
		RunTemplate("lib/Api/Api.php", inflect.Camelize(k)+".php", data)
		delete(data.Api, "active")
	}
}

func FunctionsPhp(fnc map[string]interface{}) {
	args := fnc["args"].(map[string]interface{})
	path := fnc["path"].(map[string]interface{})
	prnt := fnc["prnt"].(map[string]interface{})

	args["php"] = ArgsFunctionMaker("$", ", ")
	path["php"] = PathFunctionMaker("'.rawurlencode(", "$$this->", ").'")
	prnt["php"] = PrntFunctionMaker(false, "    ", "\"", "\"", "array(", ")", "array(", ")", "'", "' => ")
}

func CheckPhp(data *Data) error {
	if data.Pkg.Php.Vendor == "" {
		return errors.New("php.vendor is needed in pkg.json for generating php library")
	}

	return nil
}
<commit_msg>Fix PathFunctionMaker for php, fixes #37<commit_after>package alpaca

import (
	"bitbucket.org/pkg/inflect"
	"errors"
)

func WritePhp(data *Data) {
	MakeLibraryDir("php")
	RunTemplate := ChooseTemplate("php")

	RunTemplate("gitignore", ".gitignore", data)
	RunTemplate("composer.json", "composer.json", data)
	RunTemplate("readme.md", "README.md", data)

	MakeDir("lib")

	MakeDir(inflect.Camelize(data.Pkg.Name))
	RunTemplate("lib/Client.php", "Client.php", data)

	MakeDir("Exception")
	RunTemplate("lib/Exception/ExceptionInterface.php", "ExceptionInterface.php", data)
	RunTemplate("lib/Exception/ClientException.php", "ClientException.php", data)
	MoveDir("..")

	MakeDir("HttpClient")
	RunTemplate("lib/HttpClient/HttpClient.php", "HttpClient.php", data)
	RunTemplate("lib/HttpClient/AuthHandler.php", "AuthHandler.php", data)
	RunTemplate("lib/HttpClient/ErrorHandler.php", "ErrorHandler.php", data)
	RunTemplate("lib/HttpClient/RequestHandler.php", "RequestHandler.php", data)
	RunTemplate("lib/HttpClient/Response.php", "Response.php", data)
	RunTemplate("lib/HttpClient/ResponseHandler.php", "ResponseHandler.php", data)
	MoveDir("..")

	MakeDir("Api")

	for k, v := range data.Api["class"].(map[string]interface{}) {
		data.Api["active"] = ActiveClassInfo(k, v)
		RunTemplate("lib/Api/Api.php", inflect.Camelize(k)+".php", data)
		delete(data.Api, "active")
	}
}

func FunctionsPhp(fnc map[string]interface{}) {
	args := fnc["args"].(map[string]interface{})
	path := fnc["path"].(map[string]interface{})
	prnt := fnc["prnt"].(map[string]interface{})

	args["php"] = ArgsFunctionMaker("$", ", ")
	path["php"] = PathFunctionMaker("'.rawurlencode($$", "this->", ").'")
	prnt["php"] = PrntFunctionMaker(false, "    ", "\"", "\"", "array(", ")", "array(", ")", "'", "' => ")
}

func CheckPhp(data *Data) error {
	if data.Pkg.Php.Vendor == "" {
		return errors.New("php.vendor is needed in pkg.json for generating php library")
	}

	return nil
}
<|endoftext|>


<commit_before>// +build !windows

package containerd

import (
	"context"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"sync"
	"syscall"

	"github.com/containerd/fifo"
)

// NewFifos returns a new set of fifos for the task
func NewFifos(id string) (*FIFOSet, error) {
	root := filepath.Join(os.TempDir(), "containerd")
	if err := os.MkdirAll(root, 0700); err != nil {
		return nil, err
	}
	dir, err := ioutil.TempDir(root, "")
	if err != nil {
		return nil, err
	}
	return &FIFOSet{
		Dir: dir,
		In:  filepath.Join(dir, id+"-stdin"),
		Out: filepath.Join(dir, id+"-stdout"),
		Err: filepath.Join(dir, id+"-stderr"),
	}, nil
}

func copyIO(fifos *FIFOSet, ioset *ioSet, tty bool) (_ *wgCloser, err error) {
	var (
		f           io.ReadWriteCloser
		set         []io.Closer
		cwg         sync.WaitGroup
		ctx, cancel = context.WithCancel(context.Background())
		wg          = &sync.WaitGroup{}
	)
	defer func() {
		if err != nil {
			for _, f := range set {
				f.Close()
			}
			cancel()
		}
	}()

	if f, err = fifo.OpenFifo(ctx, fifos.In, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
		return nil, err
	}
	set = append(set, f)
	cwg.Add(1)
	wg.Add(1)
	go func(w io.WriteCloser) {
		cwg.Done()
		io.Copy(w, ioset.in)
		w.Close()
		wg.Done()
	}(f)

	if f, err = fifo.OpenFifo(ctx, fifos.Out, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
		return nil, err
	}
	set = append(set, f)
	wg.Add(1)
	cwg.Add(1)
	go func(r io.ReadCloser) {
		cwg.Done()
		io.Copy(ioset.out, r)
		r.Close()
		wg.Done()
	}(f)

	if f, err = fifo.OpenFifo(ctx, fifos.Err, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
		return nil, err
	}
	set = append(set, f)

	if !tty {
		wg.Add(1)
		cwg.Add(1)
		go func(r io.ReadCloser) {
			cwg.Done()
			io.Copy(ioset.err, r)
			r.Close()
			wg.Done()
		}(f)
	}
	cwg.Wait()
	return &wgCloser{
		wg:     wg,
		dir:    fifos.Dir,
		set:    set,
		cancel: cancel,
	}, nil
}
<commit_msg>Revert part of 06dc87ae59cca1536a3a98741a267af687b6dcdd<commit_after>// +build !windows

package containerd

import (
	"context"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"sync"
	"syscall"

	"github.com/containerd/fifo"
)

// NewFifos returns a new set of fifos for the task
func NewFifos(id string) (*FIFOSet, error) {
	root := filepath.Join(os.TempDir(), "containerd")
	if err := os.MkdirAll(root, 0700); err != nil {
		return nil, err
	}
	dir, err := ioutil.TempDir(root, "")
	if err != nil {
		return nil, err
	}
	return &FIFOSet{
		Dir: dir,
		In:  filepath.Join(dir, id+"-stdin"),
		Out: filepath.Join(dir, id+"-stdout"),
		Err: filepath.Join(dir, id+"-stderr"),
	}, nil
}

func copyIO(fifos *FIFOSet, ioset *ioSet, tty bool) (_ *wgCloser, err error) {
	var (
		f           io.ReadWriteCloser
		set         []io.Closer
		cwg         sync.WaitGroup
		ctx, cancel = context.WithCancel(context.Background())
		wg          = &sync.WaitGroup{}
	)
	defer func() {
		if err != nil {
			for _, f := range set {
				f.Close()
			}
			cancel()
		}
	}()

	if f, err = fifo.OpenFifo(ctx, fifos.In, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
		return nil, err
	}
	set = append(set, f)
	cwg.Add(1)
	go func(w io.WriteCloser) {
		cwg.Done()
		io.Copy(w, ioset.in)
		w.Close()
	}(f)

	if f, err = fifo.OpenFifo(ctx, fifos.Out, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
		return nil, err
	}
	set = append(set, f)
	wg.Add(1)
	cwg.Add(1)
	go func(r io.ReadCloser) {
		cwg.Done()
		io.Copy(ioset.out, r)
		r.Close()
		wg.Done()
	}(f)

	if f, err = fifo.OpenFifo(ctx, fifos.Err, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
		return nil, err
	}
	set = append(set, f)

	if !tty {
		wg.Add(1)
		cwg.Add(1)
		go func(r io.ReadCloser) {
			cwg.Done()
			io.Copy(ioset.err, r)
			r.Close()
			wg.Done()
		}(f)
	}
	cwg.Wait()
	return &wgCloser{
		wg:     wg,
		dir:    fifos.Dir,
		set:    set,
		cancel: cancel,
	}, nil
}
<|endoftext|>


<commit_before>package expr

import (
	"encoding/json"
	"fmt"
	"strconv"
	"time"

	"github.com/grafana/grafana-plugin-sdk-go/backend"
	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/components/simplejson"
	"github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/tsdb"
	"golang.org/x/net/context"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

func WrapTransformData(ctx context.Context, query *tsdb.TsdbQuery) (*tsdb.Response, error) {
	sdkReq := &backend.QueryDataRequest{
		PluginContext: backend.PluginContext{
			OrgID: query.User.OrgId,
		},
		Queries: []backend.DataQuery{},
	}

	for _, q := range query.Queries {
		modelJSON, err := q.Model.MarshalJSON()
		if err != nil {
			return nil, err
		}
		sdkReq.Queries = append(sdkReq.Queries, backend.DataQuery{
			JSON:          modelJSON,
			Interval:      time.Duration(q.IntervalMs) * time.Millisecond,
			RefID:         q.RefId,
			MaxDataPoints: q.MaxDataPoints,
			QueryType:     q.QueryType,
			TimeRange: backend.TimeRange{
				From: query.TimeRange.GetFromAsTimeUTC(),
				To:   query.TimeRange.GetToAsTimeUTC(),
			},
		})
	}
	pbRes, err := TransformData(ctx, sdkReq)
	if err != nil {
		return nil, err
	}

	tR := &tsdb.Response{
		Results: make(map[string]*tsdb.QueryResult, len(pbRes.Responses)),
	}
	for refID, res := range pbRes.Responses {
		tRes := &tsdb.QueryResult{
			RefId:      refID,
			Dataframes: tsdb.NewDecodedDataFrames(res.Frames),
		}
		// if len(res.JsonMeta) != 0 {
		// 	tRes.Meta = simplejson.NewFromAny(res.JsonMeta)
		// }
		if res.Error != nil {
			tRes.Error = res.Error
			tRes.ErrorString = res.Error.Error()
		}
		tR.Results[refID] = tRes
	}

	return tR, nil
}

// TransformData takes Queries which are either expressions nodes
// or are datasource requests.
func TransformData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
	svc := Service{}
	// Build the pipeline from the request, checking for ordering issues (e.g. loops)
	// and parsing graph nodes from the queries.
	pipeline, err := svc.BuildPipeline(req)
	if err != nil {
		return nil, status.Error(codes.InvalidArgument, err.Error())
	}

	// Execute the pipeline
	responses, err := svc.ExecutePipeline(ctx, pipeline)
	if err != nil {
		return nil, status.Error(codes.Unknown, err.Error())
	}

	// Get which queries have the Hide property so they those queries' results
	// can be excluded from the response.
	hidden, err := hiddenRefIDs(req.Queries)
	if err != nil {
		return nil, status.Error((codes.Internal), err.Error())
	}

	if len(hidden) != 0 {
		filteredRes := backend.NewQueryDataResponse()
		for refID, res := range responses.Responses {
			if _, ok := hidden[refID]; !ok {
				filteredRes.Responses[refID] = res
			}
		}
		responses = filteredRes
	}

	return responses, nil
}

func hiddenRefIDs(queries []backend.DataQuery) (map[string]struct{}, error) {
	hidden := make(map[string]struct{})

	for _, query := range queries {
		hide := struct {
			Hide bool `json:"hide"`
		}{}

		if err := json.Unmarshal(query.JSON, &hide); err != nil {
			return nil, err
		}

		if hide.Hide {
			hidden[query.RefID] = struct{}{}
		}
	}
	return hidden, nil
}

// QueryData is called used to query datasources that are not expression commands, but are used
// alongside expressions and/or are the input of an expression command.
func QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
	if len(req.Queries) == 0 {
		return nil, fmt.Errorf("zero queries found in datasource request")
	}

	datasourceID := int64(0)

	if req.PluginContext.DataSourceInstanceSettings != nil {
		datasourceID = req.PluginContext.DataSourceInstanceSettings.ID
	}

	getDsInfo := &models.GetDataSourceByIdQuery{
		OrgId: req.PluginContext.OrgID,
		Id:    datasourceID,
	}

	if err := bus.Dispatch(getDsInfo); err != nil {
		return nil, fmt.Errorf("could not find datasource: %w", err)
	}

	// Convert plugin-model (datasource) queries to tsdb queries
	queries := make([]*tsdb.Query, len(req.Queries))
	for i, query := range req.Queries {
		sj, err := simplejson.NewJson(query.JSON)
		if err != nil {
			return nil, err
		}
		queries[i] = &tsdb.Query{
			RefId:         query.RefID,
			IntervalMs:    query.Interval.Microseconds(),
			MaxDataPoints: query.MaxDataPoints,
			QueryType:     query.QueryType,
			DataSource:    getDsInfo.Result,
			Model:         sj,
		}
	}

	// For now take Time Range from first query.
	timeRange := tsdb.NewTimeRange(strconv.FormatInt(req.Queries[0].TimeRange.From.Unix()*1000, 10), strconv.FormatInt(req.Queries[0].TimeRange.To.Unix()*1000, 10))

	tQ := &tsdb.TsdbQuery{
		TimeRange: timeRange,
		Queries:   queries,
	}

	// Execute the converted queries
	tsdbRes, err := tsdb.HandleRequest(ctx, getDsInfo.Result, tQ)
	if err != nil {
		return nil, err
	}
	// Convert tsdb results (map) to plugin-model/datasource (slice) results.
	// Only error, tsdb.Series, and encoded Dataframes responses are mapped.
	responses := make(map[string]backend.DataResponse, len(tsdbRes.Results))
	for refID, res := range tsdbRes.Results {
		pRes := backend.DataResponse{}
		if res.Error != nil {
			pRes.Error = res.Error
		}

		if res.Dataframes != nil {
			decoded, err := res.Dataframes.Decoded()
			if err != nil {
				return nil, err
			}
			pRes.Frames = decoded
			responses[refID] = pRes
			continue
		}

		for _, series := range res.Series {
			frame, err := tsdb.SeriesToFrame(series)
			frame.RefID = refID
			if err != nil {
				return nil, err
			}
			pRes.Frames = append(pRes.Frames, frame)
		}

		responses[refID] = pRes
	}
	return &backend.QueryDataResponse{
		Responses: responses,
	}, nil
}
<commit_msg>Expr: fix time unit typo in ds queries (#29668)<commit_after>package expr

import (
	"encoding/json"
	"fmt"
	"strconv"
	"time"

	"github.com/grafana/grafana-plugin-sdk-go/backend"
	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/components/simplejson"
	"github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/tsdb"
	"golang.org/x/net/context"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

func WrapTransformData(ctx context.Context, query *tsdb.TsdbQuery) (*tsdb.Response, error) {
	sdkReq := &backend.QueryDataRequest{
		PluginContext: backend.PluginContext{
			OrgID: query.User.OrgId,
		},
		Queries: []backend.DataQuery{},
	}

	for _, q := range query.Queries {
		modelJSON, err := q.Model.MarshalJSON()
		if err != nil {
			return nil, err
		}
		sdkReq.Queries = append(sdkReq.Queries, backend.DataQuery{
			JSON:          modelJSON,
			Interval:      time.Duration(q.IntervalMs) * time.Millisecond,
			RefID:         q.RefId,
			MaxDataPoints: q.MaxDataPoints,
			QueryType:     q.QueryType,
			TimeRange: backend.TimeRange{
				From: query.TimeRange.GetFromAsTimeUTC(),
				To:   query.TimeRange.GetToAsTimeUTC(),
			},
		})
	}
	pbRes, err := TransformData(ctx, sdkReq)
	if err != nil {
		return nil, err
	}

	tR := &tsdb.Response{
		Results: make(map[string]*tsdb.QueryResult, len(pbRes.Responses)),
	}
	for refID, res := range pbRes.Responses {
		tRes := &tsdb.QueryResult{
			RefId:      refID,
			Dataframes: tsdb.NewDecodedDataFrames(res.Frames),
		}
		// if len(res.JsonMeta) != 0 {
		// 	tRes.Meta = simplejson.NewFromAny(res.JsonMeta)
		// }
		if res.Error != nil {
			tRes.Error = res.Error
			tRes.ErrorString = res.Error.Error()
		}
		tR.Results[refID] = tRes
	}

	return tR, nil
}

// TransformData takes Queries which are either expressions nodes
// or are datasource requests.
func TransformData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
	svc := Service{}
	// Build the pipeline from the request, checking for ordering issues (e.g. loops)
	// and parsing graph nodes from the queries.
	pipeline, err := svc.BuildPipeline(req)
	if err != nil {
		return nil, status.Error(codes.InvalidArgument, err.Error())
	}

	// Execute the pipeline
	responses, err := svc.ExecutePipeline(ctx, pipeline)
	if err != nil {
		return nil, status.Error(codes.Unknown, err.Error())
	}

	// Get which queries have the Hide property so they those queries' results
	// can be excluded from the response.
	hidden, err := hiddenRefIDs(req.Queries)
	if err != nil {
		return nil, status.Error((codes.Internal), err.Error())
	}

	if len(hidden) != 0 {
		filteredRes := backend.NewQueryDataResponse()
		for refID, res := range responses.Responses {
			if _, ok := hidden[refID]; !ok {
				filteredRes.Responses[refID] = res
			}
		}
		responses = filteredRes
	}

	return responses, nil
}

func hiddenRefIDs(queries []backend.DataQuery) (map[string]struct{}, error) {
	hidden := make(map[string]struct{})

	for _, query := range queries {
		hide := struct {
			Hide bool `json:"hide"`
		}{}

		if err := json.Unmarshal(query.JSON, &hide); err != nil {
			return nil, err
		}

		if hide.Hide {
			hidden[query.RefID] = struct{}{}
		}
	}
	return hidden, nil
}

// QueryData is called used to query datasources that are not expression commands, but are used
// alongside expressions and/or are the input of an expression command.
func QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
	if len(req.Queries) == 0 {
		return nil, fmt.Errorf("zero queries found in datasource request")
	}

	datasourceID := int64(0)

	if req.PluginContext.DataSourceInstanceSettings != nil {
		datasourceID = req.PluginContext.DataSourceInstanceSettings.ID
	}

	getDsInfo := &models.GetDataSourceByIdQuery{
		OrgId: req.PluginContext.OrgID,
		Id:    datasourceID,
	}

	if err := bus.Dispatch(getDsInfo); err != nil {
		return nil, fmt.Errorf("could not find datasource: %w", err)
	}

	// Convert plugin-model (datasource) queries to tsdb queries
	queries := make([]*tsdb.Query, len(req.Queries))
	for i, query := range req.Queries {
		sj, err := simplejson.NewJson(query.JSON)
		if err != nil {
			return nil, err
		}
		queries[i] = &tsdb.Query{
			RefId:         query.RefID,
			IntervalMs:    query.Interval.Milliseconds(),
			MaxDataPoints: query.MaxDataPoints,
			QueryType:     query.QueryType,
			DataSource:    getDsInfo.Result,
			Model:         sj,
		}
	}

	// For now take Time Range from first query.
	timeRange := tsdb.NewTimeRange(strconv.FormatInt(req.Queries[0].TimeRange.From.Unix()*1000, 10), strconv.FormatInt(req.Queries[0].TimeRange.To.Unix()*1000, 10))

	tQ := &tsdb.TsdbQuery{
		TimeRange: timeRange,
		Queries:   queries,
	}

	// Execute the converted queries
	tsdbRes, err := tsdb.HandleRequest(ctx, getDsInfo.Result, tQ)
	if err != nil {
		return nil, err
	}
	// Convert tsdb results (map) to plugin-model/datasource (slice) results.
	// Only error, tsdb.Series, and encoded Dataframes responses are mapped.
	responses := make(map[string]backend.DataResponse, len(tsdbRes.Results))
	for refID, res := range tsdbRes.Results {
		pRes := backend.DataResponse{}
		if res.Error != nil {
			pRes.Error = res.Error
		}

		if res.Dataframes != nil {
			decoded, err := res.Dataframes.Decoded()
			if err != nil {
				return nil, err
			}
			pRes.Frames = decoded
			responses[refID] = pRes
			continue
		}

		for _, series := range res.Series {
			frame, err := tsdb.SeriesToFrame(series)
			frame.RefID = refID
			if err != nil {
				return nil, err
			}
			pRes.Frames = append(pRes.Frames, frame)
		}

		responses[refID] = pRes
	}
	return &backend.QueryDataResponse{
		Responses: responses,
	}, nil
}
<|endoftext|>


<commit_before>package sqlstore

import (
	"bytes"
	"fmt"
	"strings"
	"time"

	"github.com/grafana/grafana/pkg/bus"
	m "github.com/grafana/grafana/pkg/models"
)

func init() {
	bus.AddHandler("sql", SaveAlerts)
	bus.AddHandler("sql", HandleAlertsQuery)
	bus.AddHandler("sql", GetAlertById)
	bus.AddHandler("sql", DeleteAlertById)
	bus.AddHandler("sql", GetAllAlertQueryHandler)
	bus.AddHandler("sql", SetAlertState)
	bus.AddHandler("sql", GetAlertStatesForDashboard)
	bus.AddHandler("sql", PauseAlert)
	bus.AddHandler("sql", PauseAllAlerts)
}

func GetAlertById(query *m.GetAlertByIdQuery) error {
	alert := m.Alert{}
	has, err := x.Id(query.Id).Get(&alert)
	if !has {
		return fmt.Errorf("could not find alert")
	}
	if err != nil {
		return err
	}

	query.Result = &alert
	return nil
}

func GetAllAlertQueryHandler(query *m.GetAllAlertsQuery) error {
	var alerts []*m.Alert
	err := x.Sql("select * from alert").Find(&alerts)
	if err != nil {
		return err
	}

	query.Result = alerts
	return nil
}

func deleteAlertByIdInternal(alertId int64, reason string, sess *DBSession) error {
	sqlog.Debug("Deleting alert", "id", alertId, "reason", reason)

	if _, err := sess.Exec("DELETE FROM alert WHERE id = ?", alertId); err != nil {
		return err
	}

	if _, err := sess.Exec("DELETE FROM annotation WHERE alert_id = ?", alertId); err != nil {
		return err
	}

	return nil
}

func DeleteAlertById(cmd *m.DeleteAlertCommand) error {
	return inTransaction(func(sess *DBSession) error {
		return deleteAlertByIdInternal(cmd.AlertId, "DeleteAlertCommand", sess)
	})
}

func HandleAlertsQuery(query *m.GetAlertsQuery) error {
	var sql bytes.Buffer
	params := make([]interface{}, 0)

	sql.WriteString(`SELECT *
						from alert
						`)

	sql.WriteString(`WHERE org_id = ?`)
	params = append(params, query.OrgId)

	if query.DashboardId != 0 {
		sql.WriteString(` AND dashboard_id = ?`)
		params = append(params, query.DashboardId)
	}

	if query.PanelId != 0 {
		sql.WriteString(` AND panel_id = ?`)
		params = append(params, query.PanelId)
	}

	if len(query.State) > 0 && query.State[0] != "ALL" {
		sql.WriteString(` AND (`)
		for i, v := range query.State {
			if i > 0 {
				sql.WriteString(" OR ")
			}
			sql.WriteString("state = ? ")
			params = append(params, v)
		}
		sql.WriteString(")")
	}

	if query.Limit != 0 {
		sql.WriteString(" LIMIT ?")
		params = append(params, query.Limit)
	}

	sql.WriteString(" ORDER BY name ASC")

	alerts := make([]*m.Alert, 0)
	if err := x.Sql(sql.String(), params...).Find(&alerts); err != nil {
		return err
	}

	for i := range alerts {
		if alerts[i].ExecutionError == " " {
			alerts[i].ExecutionError = ""
		}
	}

	query.Result = alerts
	return nil
}

func DeleteAlertDefinition(dashboardId int64, sess *DBSession) error {
	alerts := make([]*m.Alert, 0)
	sess.Where("dashboard_id = ?", dashboardId).Find(&alerts)

	for _, alert := range alerts {
		deleteAlertByIdInternal(alert.Id, "Dashboard deleted", sess)
	}

	return nil
}

func SaveAlerts(cmd *m.SaveAlertsCommand) error {
	return inTransaction(func(sess *DBSession) error {
		existingAlerts, err := GetAlertsByDashboardId2(cmd.DashboardId, sess)
		if err != nil {
			return err
		}

		if err := upsertAlerts(existingAlerts, cmd, sess); err != nil {
			return err
		}

		if err := deleteMissingAlerts(existingAlerts, cmd, sess); err != nil {
			return err
		}

		return nil
	})
}

func upsertAlerts(existingAlerts []*m.Alert, cmd *m.SaveAlertsCommand, sess *DBSession) error {
	for _, alert := range cmd.Alerts {
		update := false
		var alertToUpdate *m.Alert

		for _, k := range existingAlerts {
			if alert.PanelId == k.PanelId {
				update = true
				alert.Id = k.Id
				alertToUpdate = k
				break
			}
		}

		if update {
			if alertToUpdate.ContainsUpdates(alert) {
				alert.Updated = time.Now()
				alert.State = alertToUpdate.State
				sess.MustCols("message")
				_, err := sess.Id(alert.Id).Update(alert)
				if err != nil {
					return err
				}

				sqlog.Debug("Alert updated", "name", alert.Name, "id", alert.Id)
			}
		} else {
			alert.Updated = time.Now()
			alert.Created = time.Now()
			alert.State = m.AlertStatePending
			alert.NewStateDate = time.Now()

			_, err := sess.Insert(alert)
			if err != nil {
				return err
			}

			sqlog.Debug("Alert inserted", "name", alert.Name, "id", alert.Id)
		}
	}

	return nil
}

func deleteMissingAlerts(alerts []*m.Alert, cmd *m.SaveAlertsCommand, sess *DBSession) error {
	for _, missingAlert := range alerts {
		missing := true

		for _, k := range cmd.Alerts {
			if missingAlert.PanelId == k.PanelId {
				missing = false
				break
			}
		}

		if missing {
			deleteAlertByIdInternal(missingAlert.Id, "Removed from dashboard", sess)
		}
	}

	return nil
}

func GetAlertsByDashboardId2(dashboardId int64, sess *DBSession) ([]*m.Alert, error) {
	alerts := make([]*m.Alert, 0)
	err := sess.Where("dashboard_id = ?", dashboardId).Find(&alerts)

	if err != nil {
		return []*m.Alert{}, err
	}

	return alerts, nil
}

func SetAlertState(cmd *m.SetAlertStateCommand) error {
	return inTransaction(func(sess *DBSession) error {
		alert := m.Alert{}

		if has, err := sess.Id(cmd.AlertId).Get(&alert); err != nil {
			return err
		} else if !has {
			return fmt.Errorf("Could not find alert")
		}

		if alert.State == m.AlertStatePaused {
			return m.ErrCannotChangeStateOnPausedAlert
		}

		if alert.State == cmd.State {
			return m.ErrRequiresNewState
		}

		alert.State = cmd.State
		alert.StateChanges += 1
		alert.NewStateDate = time.Now()
		alert.EvalData = cmd.EvalData

		if cmd.Error == "" {
			alert.ExecutionError = " " //without this space, xorm skips updating this field
		} else {
			alert.ExecutionError = cmd.Error
		}

		sess.Id(alert.Id).Update(&alert)
		return nil
	})
}

func PauseAlert(cmd *m.PauseAlertCommand) error {
	return inTransaction(func(sess *DBSession) error {
		if len(cmd.AlertIds) == 0 {
			return fmt.Errorf("command contains no alertids")
		}

		var buffer bytes.Buffer
		params := make([]interface{}, 0)

		buffer.WriteString(`UPDATE alert SET state = ?`)
		if cmd.Paused {
			params = append(params, string(m.AlertStatePaused))
		} else {
			params = append(params, string(m.AlertStatePending))
		}

		buffer.WriteString(` WHERE id IN (?` + strings.Repeat(",?", len(cmd.AlertIds)-1) + `)`)
		for _, v := range cmd.AlertIds {
			params = append(params, v)
		}

		res, err := sess.Exec(buffer.String(), params...)
		if err != nil {
			return err
		}
		cmd.ResultCount, _ = res.RowsAffected()
		return nil
	})
}

func PauseAllAlerts(cmd *m.PauseAllAlertCommand) error {
	return inTransaction(func(sess *DBSession) error {
		var newState string
		if cmd.Paused {
			newState = string(m.AlertStatePaused)
		} else {
			newState = string(m.AlertStatePending)
		}

		res, err := sess.Exec(`UPDATE alert SET state = ?`, newState)
		if err != nil {
			return err
		}
		cmd.ResultCount, _ = res.RowsAffected()
		return nil
	})
}

func GetAlertStatesForDashboard(query *m.GetAlertStatesForDashboardQuery) error {
	var rawSql = `SELECT
	                id,
	                dashboard_id,
	                panel_id,
	                state,
	                new_state_date
	                FROM alert
	                WHERE org_id = ? AND dashboard_id = ?`

	query.Result = make([]*m.AlertStateInfoDTO, 0)
	err := x.Sql(rawSql, query.OrgId, query.DashboardId).Find(&query.Result)

	return err
}
<commit_msg>fix: alert api limit param did not work and caused SQL syntax error, fixes #9492<commit_after>package sqlstore

import (
	"bytes"
	"fmt"
	"strings"
	"time"

	"github.com/grafana/grafana/pkg/bus"
	m "github.com/grafana/grafana/pkg/models"
)

func init() {
	bus.AddHandler("sql", SaveAlerts)
	bus.AddHandler("sql", HandleAlertsQuery)
	bus.AddHandler("sql", GetAlertById)
	bus.AddHandler("sql", DeleteAlertById)
	bus.AddHandler("sql", GetAllAlertQueryHandler)
	bus.AddHandler("sql", SetAlertState)
	bus.AddHandler("sql", GetAlertStatesForDashboard)
	bus.AddHandler("sql", PauseAlert)
	bus.AddHandler("sql", PauseAllAlerts)
}

func GetAlertById(query *m.GetAlertByIdQuery) error {
	alert := m.Alert{}
	has, err := x.Id(query.Id).Get(&alert)
	if !has {
		return fmt.Errorf("could not find alert")
	}
	if err != nil {
		return err
	}

	query.Result = &alert
	return nil
}

func GetAllAlertQueryHandler(query *m.GetAllAlertsQuery) error {
	var alerts []*m.Alert
	err := x.Sql("select * from alert").Find(&alerts)
	if err != nil {
		return err
	}

	query.Result = alerts
	return nil
}

func deleteAlertByIdInternal(alertId int64, reason string, sess *DBSession) error {
	sqlog.Debug("Deleting alert", "id", alertId, "reason", reason)

	if _, err := sess.Exec("DELETE FROM alert WHERE id = ?", alertId); err != nil {
		return err
	}

	if _, err := sess.Exec("DELETE FROM annotation WHERE alert_id = ?", alertId); err != nil {
		return err
	}

	return nil
}

func DeleteAlertById(cmd *m.DeleteAlertCommand) error {
	return inTransaction(func(sess *DBSession) error {
		return deleteAlertByIdInternal(cmd.AlertId, "DeleteAlertCommand", sess)
	})
}

func HandleAlertsQuery(query *m.GetAlertsQuery) error {
	var sql bytes.Buffer
	params := make([]interface{}, 0)

	sql.WriteString(`SELECT *
						from alert
						`)

	sql.WriteString(`WHERE org_id = ?`)
	params = append(params, query.OrgId)

	if query.DashboardId != 0 {
		sql.WriteString(` AND dashboard_id = ?`)
		params = append(params, query.DashboardId)
	}

	if query.PanelId != 0 {
		sql.WriteString(` AND panel_id = ?`)
		params = append(params, query.PanelId)
	}

	if len(query.State) > 0 && query.State[0] != "ALL" {
		sql.WriteString(` AND (`)
		for i, v := range query.State {
			if i > 0 {
				sql.WriteString(" OR ")
			}
			sql.WriteString("state = ? ")
			params = append(params, v)
		}
		sql.WriteString(")")
	}

	sql.WriteString(" ORDER BY name ASC")

	if query.Limit != 0 {
		sql.WriteString(" LIMIT ?")
		params = append(params, query.Limit)
	}

	alerts := make([]*m.Alert, 0)
	if err := x.Sql(sql.String(), params...).Find(&alerts); err != nil {
		return err
	}

	for i := range alerts {
		if alerts[i].ExecutionError == " " {
			alerts[i].ExecutionError = ""
		}
	}

	query.Result = alerts
	return nil
}

func DeleteAlertDefinition(dashboardId int64, sess *DBSession) error {
	alerts := make([]*m.Alert, 0)
	sess.Where("dashboard_id = ?", dashboardId).Find(&alerts)

	for _, alert := range alerts {
		deleteAlertByIdInternal(alert.Id, "Dashboard deleted", sess)
	}

	return nil
}

func SaveAlerts(cmd *m.SaveAlertsCommand) error {
	return inTransaction(func(sess *DBSession) error {
		existingAlerts, err := GetAlertsByDashboardId2(cmd.DashboardId, sess)
		if err != nil {
			return err
		}

		if err := upsertAlerts(existingAlerts, cmd, sess); err != nil {
			return err
		}

		if err := deleteMissingAlerts(existingAlerts, cmd, sess); err != nil {
			return err
		}

		return nil
	})
}

func upsertAlerts(existingAlerts []*m.Alert, cmd *m.SaveAlertsCommand, sess *DBSession) error {
	for _, alert := range cmd.Alerts {
		update := false
		var alertToUpdate *m.Alert

		for _, k := range existingAlerts {
			if alert.PanelId == k.PanelId {
				update = true
				alert.Id = k.Id
				alertToUpdate = k
				break
			}
		}

		if update {
			if alertToUpdate.ContainsUpdates(alert) {
				alert.Updated = time.Now()
				alert.State = alertToUpdate.State
				sess.MustCols("message")
				_, err := sess.Id(alert.Id).Update(alert)
				if err != nil {
					return err
				}

				sqlog.Debug("Alert updated", "name", alert.Name, "id", alert.Id)
			}
		} else {
			alert.Updated = time.Now()
			alert.Created = time.Now()
			alert.State = m.AlertStatePending
			alert.NewStateDate = time.Now()

			_, err := sess.Insert(alert)
			if err != nil {
				return err
			}

			sqlog.Debug("Alert inserted", "name", alert.Name, "id", alert.Id)
		}
	}

	return nil
}

func deleteMissingAlerts(alerts []*m.Alert, cmd *m.SaveAlertsCommand, sess *DBSession) error {
	for _, missingAlert := range alerts {
		missing := true

		for _, k := range cmd.Alerts {
			if missingAlert.PanelId == k.PanelId {
				missing = false
				break
			}
		}

		if missing {
			deleteAlertByIdInternal(missingAlert.Id, "Removed from dashboard", sess)
		}
	}

	return nil
}

func GetAlertsByDashboardId2(dashboardId int64, sess *DBSession) ([]*m.Alert, error) {
	alerts := make([]*m.Alert, 0)
	err := sess.Where("dashboard_id = ?", dashboardId).Find(&alerts)

	if err != nil {
		return []*m.Alert{}, err
	}

	return alerts, nil
}

func SetAlertState(cmd *m.SetAlertStateCommand) error {
	return inTransaction(func(sess *DBSession) error {
		alert := m.Alert{}

		if has, err := sess.Id(cmd.AlertId).Get(&alert); err != nil {
			return err
		} else if !has {
			return fmt.Errorf("Could not find alert")
		}

		if alert.State == m.AlertStatePaused {
			return m.ErrCannotChangeStateOnPausedAlert
		}

		if alert.State == cmd.State {
			return m.ErrRequiresNewState
		}

		alert.State = cmd.State
		alert.StateChanges += 1
		alert.NewStateDate = time.Now()
		alert.EvalData = cmd.EvalData

		if cmd.Error == "" {
			alert.ExecutionError = " " //without this space, xorm skips updating this field
		} else {
			alert.ExecutionError = cmd.Error
		}

		sess.Id(alert.Id).Update(&alert)
		return nil
	})
}

func PauseAlert(cmd *m.PauseAlertCommand) error {
	return inTransaction(func(sess *DBSession) error {
		if len(cmd.AlertIds) == 0 {
			return fmt.Errorf("command contains no alertids")
		}

		var buffer bytes.Buffer
		params := make([]interface{}, 0)

		buffer.WriteString(`UPDATE alert SET state = ?`)
		if cmd.Paused {
			params = append(params, string(m.AlertStatePaused))
		} else {
			params = append(params, string(m.AlertStatePending))
		}

		buffer.WriteString(` WHERE id IN (?` + strings.Repeat(",?", len(cmd.AlertIds)-1) + `)`)
		for _, v := range cmd.AlertIds {
			params = append(params, v)
		}

		res, err := sess.Exec(buffer.String(), params...)
		if err != nil {
			return err
		}
		cmd.ResultCount, _ = res.RowsAffected()
		return nil
	})
}

func PauseAllAlerts(cmd *m.PauseAllAlertCommand) error {
	return inTransaction(func(sess *DBSession) error {
		var newState string
		if cmd.Paused {
			newState = string(m.AlertStatePaused)
		} else {
			newState = string(m.AlertStatePending)
		}

		res, err := sess.Exec(`UPDATE alert SET state = ?`, newState)
		if err != nil {
			return err
		}
		cmd.ResultCount, _ = res.RowsAffected()
		return nil
	})
}

func GetAlertStatesForDashboard(query *m.GetAlertStatesForDashboardQuery) error {
	var rawSql = `SELECT
	                id,
	                dashboard_id,
	                panel_id,
	                state,
	                new_state_date
	                FROM alert
	                WHERE org_id = ? AND dashboard_id = ?`

	query.Result = make([]*m.AlertStateInfoDTO, 0)
	err := x.Sql(rawSql, query.OrgId, query.DashboardId).Find(&query.Result)

	return err
}
<|endoftext|>


<commit_before>package appmanager

import (
	"encoding/json"

	log "github.com/F5Networks/k8s-bigip-ctlr/pkg/vlogger"
)

type as3Template string
type as3Declaration string

type serviceName string
type appName string
type tenantName string

type pool []Member
type tenant map[appName][]serviceName
type as3Object map[tenantName]tenant

// Takes an AS3 Template and perform service discovery with Kubernetes to generate AS3 Declaration
func (appMgr *Manager) processUserDefinedAS3(template as3Template) {
	// TODO: Implement Me

}

// getAS3ObjectFromTemplate gets an AS3 template as a input parameter.
// It parses AS3 template, constructs an as3Object and returns it.
func (appMgr *Manager) getAS3ObjectFromTemplate(
	template as3Template,
) (as3Object, bool) {
	var tmpl interface{}
	err := json.Unmarshal([]byte(template), &tmpl)
	if err != nil {
		log.Errorf("JSON unmarshal failed: %v\n", err)
		return nil, false
	}

	as3 := make(as3Object)
	// extract as3 decleration from template
	dclr := (tmpl.(map[string]interface{}))["decleration"]

	// Loop over all the tenants
	for tn, t := range dclr.(map[string]interface{}) {
		// Filter out non-json values
		if _, ok := t.(map[string]interface{}); !ok {
			continue
		}

		as3[tenantName(tn)] = make(tenant, 0)
		// Loop over all the services in a tenant
		for an, a := range t.(map[string]interface{}) {
			// Filter out non-json values
			if _, ok := a.(map[string]interface{}); !ok {
				continue
			}

			as3[tenantName(tn)][appName(an)] = []serviceName{}
			// Loop over all the json objects in an application
			for sn, v := range a.(map[string]interface{}) {
				// Filter out non-json values
				if _, ok := v.(map[string]interface{}); !ok {
					continue
				}

				// filter out empty json objects and pool objects
				if cl := getClass(v); cl == "" || cl == "Pool" {
					continue
				}
				//Update the list of services under corresponding application
				as3[tenantName(tn)][appName(an)] = append(
					as3[tenantName(tn)][appName(an)],
					serviceName(sn),
				)
			}
			if len(as3[tenantName(tn)][appName(an)]) == 0 {
				log.Debugf("No services declared for application: %s,"+
					" tenant: %s\n", an, tn)
			}
		}
		if len(as3[tenantName(tn)]) == 0 {
			log.Debugf("No applications declared for tenant: %s\n", tn)
		}
	}
	if len(as3) == 0 {
		log.Error("No tenants declared in AS3 template")
		return as3, false
	}
	return as3, true
}

func getClass(obj interface{}) string {
	cfg := obj.(map[string]interface{})
	cl, ok := cfg["class"].(string)
	if !ok {
		log.Debugf("No class attribute found")
		return ""
	}
	return cl
}

// Story 3
// Discover Endpoints for an application. Returns a pool
func (appMgr *Manager) getEndpointsForAS3Service(tenant tenantName, app appName, as3Svc serviceName) pool {
	return pool{}
}

// Returns a pool of IP address.
func (appMgr *Manager) getFakeEndpointsForAS3Service(tenant tenantName, app appName, as3Svc serviceName) pool {
	return []Member{
		{"1.1.1.1", 80, ""},
		{"2.2.2.2", 80, ""},
		{"3.3.3.3", 80, ""},
	}
}

// Story 4
// Takes AS3 template and AS3 Object and produce AS3 Declaration
func buildAS3Declaration(obj as3Object, template as3Template) as3Declaration {
	decalaration := ""
	return as3Declaration(decalaration)
}

//Story 5
// Takes AS3 Declaration and posting it to BigIP
func (appMgr *Manager) postAS3Declaration(declaration as3Declaration) {
}
<commit_msg>Perform Service Discovery for AS3 Service<commit_after>package appmanager

import (
	"encoding/json"
	"fmt"
	log "github.com/F5Networks/k8s-bigip-ctlr/pkg/vlogger"
	metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/pkg/api/v1"
	apiv1 "k8s.io/client-go/pkg/api/v1"
)

type as3Template string
type as3Declaration string

type serviceName string
type appName string
type tenantName string

type pool []Member
type tenant map[appName][]serviceName
type as3Object map[tenantName]tenant

// Takes an AS3 Template and perform service discovery with Kubernetes to generate AS3 Declaration
func (appMgr *Manager) processUserDefinedAS3(template as3Template) {
	// TODO: Implement Me

}

// getAS3ObjectFromTemplate gets an AS3 template as a input parameter.
// It parses AS3 template, constructs an as3Object and returns it.
func (appMgr *Manager) getAS3ObjectFromTemplate(
	template as3Template,
) (as3Object, bool) {
	var tmpl interface{}
	err := json.Unmarshal([]byte(template), &tmpl)
	if err != nil {
		log.Errorf("JSON unmarshal failed: %v\n", err)
		return nil, false
	}

	as3 := make(as3Object)
	// extract as3 decleration from template
	dclr := (tmpl.(map[string]interface{}))["decleration"]

	// Loop over all the tenants
	for tn, t := range dclr.(map[string]interface{}) {
		// Filter out non-json values
		if _, ok := t.(map[string]interface{}); !ok {
			continue
		}

		as3[tenantName(tn)] = make(tenant, 0)
		// Loop over all the services in a tenant
		for an, a := range t.(map[string]interface{}) {
			// Filter out non-json values
			if _, ok := a.(map[string]interface{}); !ok {
				continue
			}

			as3[tenantName(tn)][appName(an)] = []serviceName{}
			// Loop over all the json objects in an application
			for sn, v := range a.(map[string]interface{}) {
				// Filter out non-json values
				if _, ok := v.(map[string]interface{}); !ok {
					continue
				}

				// filter out empty json objects and pool objects
				if cl := getClass(v); cl == "" || cl == "Pool" {
					continue
				}
				//Update the list of services under corresponding application
				as3[tenantName(tn)][appName(an)] = append(
					as3[tenantName(tn)][appName(an)],
					serviceName(sn),
				)
			}
			if len(as3[tenantName(tn)][appName(an)]) == 0 {
				log.Debugf("No services declared for application: %s,"+
					" tenant: %s\n", an, tn)
			}
		}
		if len(as3[tenantName(tn)]) == 0 {
			log.Debugf("No applications declared for tenant: %s\n", tn)
		}
	}
	if len(as3) == 0 {
		log.Error("No tenants declared in AS3 template")
		return as3, false
	}
	return as3, true
}

func getClass(obj interface{}) string {
	cfg := obj.(map[string]interface{})
	cl, ok := cfg["class"].(string)
	if !ok {
		log.Debugf("No class attribute found")
		return ""
	}
	return cl
}

// Performs Service discovery for the given AS3 Service and returns a pool.
// Service discovery is loosely coupled with Kubernetes Service labels. A Kubernetes Service is treated as a match for
// an AS3 service, if the Kubernetes Service have the following labels and their values matches corresponding AS3
// Object.
// cis.f5.com/as3-tenant=<Tenant Name>
// cis.f5.com/as3-app=<Application Name>
// cis.f5.com/as3-service=<AS3 Service Name>
// When a match is found, returns Node's Address and Service NodePort as pool members, if Controller is running in
// NodePort mode, else by default ClusterIP Address and Port are returned.
func (appMgr *Manager) getEndpointsForAS3Service(tenant tenantName, app appName, as3Svc serviceName) pool {
	tenantKey := "cis.f5.com/as3-tenant="
	appKey := "cis.f5.com/as3-app="
	serviceKey := "cis.f5.com/as3-service="

	selector := tenantKey + string(tenant) + "," +
		appKey + string(app) + "," +
		serviceKey + string(as3Svc)

	svcListOptions := metaV1.ListOptions{
		LabelSelector: selector,
	}

	// Identify services that matched the given label
	services, err := appMgr.kubeClient.CoreV1().Services(v1.NamespaceAll).List(svcListOptions)

	if err != nil {
		log.Errorf("[as3] Error getting service list. %v", err)
		return nil
	}

	var members []Member

	for _, service := range services.Items {
		if appMgr.isNodePort == false { // Controller is in ClusterIP Mode
			endpointsList, err := appMgr.kubeClient.CoreV1().Endpoints(service.Namespace).List(
				metaV1.ListOptions{
					FieldSelector: "metadata.name=" + service.Name,
				},
			)
			if err != nil {
				log.Debugf("[as3] Error getting endpoints for service %v", service.Name)
				continue
			}

			for _, endpoints := range endpointsList.Items {
				for _, subset := range endpoints.Subsets {
					for _, address := range subset.Addresses {
						member := Member{
							Address: address.IP,
							Port:    subset.Ports[0].Port,
						}
						members = append(members, member)
					}
				}
			}
		} else { // Controller is in NodePort mode.
			if service.Spec.Type == apiv1.ServiceTypeNodePort {
				members = appMgr.getEndpointsForNodePort(service.Spec.Ports[0].NodePort)
			} else {
				msg := fmt.Sprintf("Requested service backend '%+v' not of NodePort type", service.Name)
				log.Debug(msg)
			}
		}

		log.Debugf("[as3] Discovered members for service %v is %v", service, members)
	}

	return members
}

// Returns a pool of IP address.
func (appMgr *Manager) getFakeEndpointsForAS3Service(tenant tenantName, app appName, as3Svc serviceName) pool {
	return []Member{
		{"1.1.1.1", 80, ""},
		{"2.2.2.2", 80, ""},
		{"3.3.3.3", 80, ""},
	}
}

// Story 4
// Takes AS3 template and AS3 Object and produce AS3 Declaration
func buildAS3Declaration(obj as3Object, template as3Template) as3Declaration {
	decalaration := ""
	return as3Declaration(decalaration)
}

//Story 5
// Takes AS3 Declaration and posting it to BigIP
func (appMgr *Manager) postAS3Declaration(declaration as3Declaration) {
}
<|endoftext|>


<commit_before>package sse

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"sync"
)

func newWriter(w io.Writer) *writer {
	return &writer{w: w}
}

type writer struct {
	w   io.Writer
	mtx sync.Mutex
}

func (w *writer) WriteID(id string) error {
	w.mtx.Lock()
	defer w.mtx.Unlock()
	_, err := fmt.Fprintf(w.w, "id: %s\n", id)
	return err
}

func (w *writer) Write(p []byte) (int, error) {
	w.mtx.Lock()
	defer w.mtx.Unlock()
	for _, line := range bytes.Split(p, []byte("\n")) {
		if _, err := fmt.Fprintf(w.w, "data: %s\n", line); err != nil {
			return 0, err
		}
	}
	// add a terminating newline
	_, err := w.w.Write([]byte("\n"))
	return len(p), err
}

func (w *writer) Error(err error) (int, error) {
	w.mtx.Lock()
	defer w.mtx.Unlock()
	_, e := w.w.Write([]byte("event: error\n"))
	if e != nil {
		return 0, e
	}
	return w.Write([]byte(err.Error()))
}

func (w *writer) Flush() {
	if fw, ok := w.w.(http.Flusher); ok {
		fw.Flush()
	}
}

type Reader struct {
	*bufio.Reader
}

type Error string

func (e Error) Error() string {
	return "Server error: " + string(e)
}

func (r *Reader) Read() ([]byte, error) {
	buf := []byte{}
	var isErr bool
	for {
		line, err := r.ReadBytes('\n')
		if err != nil {
			return nil, err
		}
		if bytes.HasPrefix(line, []byte("event: error")) {
			isErr = true
		}
		if bytes.HasPrefix(line, []byte("data: ")) {
			data := bytes.TrimSuffix(bytes.TrimPrefix(line, []byte("data: ")), []byte("\n"))
			buf = append(buf, data...)
		}
		// peek ahead one byte to see if we have a double newline (terminator)
		if peek, err := r.Peek(1); err == nil && string(peek) == "\n" {
			break
		}
	}
	if isErr {
		return nil, Error(string(buf))
	}
	return buf, nil
}

type Decoder struct {
	*Reader
}

func NewDecoder(r *bufio.Reader) *Decoder {
	return &Decoder{&Reader{r}}
}

// Decode finds the next "data" field and decodes it into v
func (dec *Decoder) Decode(v interface{}) error {
	data, err := dec.Reader.Read()
	if err != nil {
		return err
	}
	return json.Unmarshal(data, v)
}
<commit_msg>pkg/sse: Fix writer.Error<commit_after>package sse

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"sync"
)

func newWriter(w io.Writer) *writer {
	return &writer{w: w}
}

type writer struct {
	w   io.Writer
	mtx sync.Mutex
}

func (w *writer) WriteID(id string) error {
	w.mtx.Lock()
	defer w.mtx.Unlock()
	_, err := fmt.Fprintf(w.w, "id: %s\n", id)
	return err
}

func (w *writer) Write(p []byte) (int, error) {
	w.mtx.Lock()
	defer w.mtx.Unlock()
	for _, line := range bytes.Split(p, []byte("\n")) {
		if _, err := fmt.Fprintf(w.w, "data: %s\n", line); err != nil {
			return 0, err
		}
	}
	// add a terminating newline
	_, err := w.w.Write([]byte("\n"))
	return len(p), err
}

func (w *writer) Error(err error) (int, error) {
	w.mtx.Lock()
	_, e := w.w.Write([]byte("event: error\n"))
	w.mtx.Unlock()
	if e != nil {
		return 0, e
	}
	return w.Write([]byte(err.Error()))
}

func (w *writer) Flush() {
	if fw, ok := w.w.(http.Flusher); ok {
		fw.Flush()
	}
}

type Reader struct {
	*bufio.Reader
}

type Error string

func (e Error) Error() string {
	return "Server error: " + string(e)
}

func (r *Reader) Read() ([]byte, error) {
	buf := []byte{}
	var isErr bool
	for {
		line, err := r.ReadBytes('\n')
		if err != nil {
			return nil, err
		}
		if bytes.HasPrefix(line, []byte("event: error")) {
			isErr = true
		}
		if bytes.HasPrefix(line, []byte("data: ")) {
			data := bytes.TrimSuffix(bytes.TrimPrefix(line, []byte("data: ")), []byte("\n"))
			buf = append(buf, data...)
		}
		// peek ahead one byte to see if we have a double newline (terminator)
		if peek, err := r.Peek(1); err == nil && string(peek) == "\n" {
			break
		}
	}
	if isErr {
		return nil, Error(string(buf))
	}
	return buf, nil
}

type Decoder struct {
	*Reader
}

func NewDecoder(r *bufio.Reader) *Decoder {
	return &Decoder{&Reader{r}}
}

// Decode finds the next "data" field and decodes it into v
func (dec *Decoder) Decode(v interface{}) error {
	data, err := dec.Reader.Read()
	if err != nil {
		return err
	}
	return json.Unmarshal(data, v)
}
<|endoftext|>


<commit_before>package mains

import (
	"bufio"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/zetamatta/nyagos/lua"
	"github.com/zetamatta/nyagos/shell"
)

func setLuaArg(L lua.Lua, args []string) {
	L.NewTable()
	for i, arg1 := range args {
		L.PushString(arg1)
		L.RawSetI(-2, lua.Integer(i))
	}
	L.SetGlobal("arg")
}

var optionNorc = false

func optionParse(it *shell.Cmd, L lua.Lua) (func() error, error) {
	args := os.Args[1:]
	for i := 0; i < len(args); i++ {
		arg1 := args[i]
		if arg1 == "-k" {
			i++
			if i >= len(args) {
				return nil, errors.New("-k: requires parameters")
			}
			return func() error {
				it.Interpret(args[i])
				return nil
			}, nil
		} else if arg1 == "-c" {
			i++
			if i >= len(args) {
				return nil, errors.New("-c: requires parameters")
			}
			return func() error {
				it.Interpret(args[i])
				return io.EOF
			}, nil
		} else if arg1 == "-b" {
			i++
			if i >= len(args) {
				return nil, errors.New("-b: requires parameters")
			}
			data, err := base64.StdEncoding.DecodeString(args[i])
			if err != nil {
				return nil, err
			}
			text := string(data)
			return func() error {
				it.Interpret(text)
				return io.EOF
			}, nil
		} else if arg1 == "-f" {
			i++
			if i >= len(args) {
				return nil, errors.New("-f: requires parameters")
			}
			if strings.HasSuffix(strings.ToLower(args[i]), ".lua") {
				// lua script
				return func() error {
					setLuaArg(L, args[i:])
					_, err := runLua(it, L, args[i])
					if err != nil {
						return err
					} else {
						return io.EOF
					}
				}, nil
			} else {
				return func() error {
					// command script
					fd, fd_err := os.Open(args[i])
					if fd_err != nil {
						return fmt.Errorf("%s: %s\n", args[i], fd_err.Error())
					}
					scanner := bufio.NewScanner(fd)
					for scanner.Scan() {
						it.Interpret(scanner.Text())
					}
					fd.Close()
					return io.EOF
				}, nil
			}
		} else if arg1 == "-e" {
			i++
			if i >= len(args) {
				return nil, errors.New("-e: requires parameters")
			}
			return func() error {
				err := L.LoadString(args[i])
				if err != nil {
					return err
				}
				setLuaArg(L, args[i:])
				L.Call(0, 0)
				return io.EOF
			}, nil
		} else if arg1 == "--norc" {
			optionNorc = true
		}
	}
	return nil, nil
}
<commit_msg>option --lua-file<commit_after>package mains

import (
	"bufio"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/zetamatta/nyagos/lua"
	"github.com/zetamatta/nyagos/shell"
)

func setLuaArg(L lua.Lua, args []string) {
	L.NewTable()
	for i, arg1 := range args {
		L.PushString(arg1)
		L.RawSetI(-2, lua.Integer(i))
	}
	L.SetGlobal("arg")
}

var optionNorc = false

func optionParse(it *shell.Cmd, L lua.Lua) (func() error, error) {
	args := os.Args[1:]
	for i := 0; i < len(args); i++ {
		arg1 := args[i]
		if arg1 == "-k" {
			i++
			if i >= len(args) {
				return nil, errors.New("-k: requires parameters")
			}
			return func() error {
				it.Interpret(args[i])
				return nil
			}, nil
		} else if arg1 == "-c" {
			i++
			if i >= len(args) {
				return nil, errors.New("-c: requires parameters")
			}
			return func() error {
				it.Interpret(args[i])
				return io.EOF
			}, nil
		} else if arg1 == "-b" {
			i++
			if i >= len(args) {
				return nil, errors.New("-b: requires parameters")
			}
			data, err := base64.StdEncoding.DecodeString(args[i])
			if err != nil {
				return nil, err
			}
			text := string(data)
			return func() error {
				it.Interpret(text)
				return io.EOF
			}, nil
		} else if arg1 == "-f" {
			i++
			if i >= len(args) {
				return nil, errors.New("-f: requires parameters")
			}
			if strings.HasSuffix(strings.ToLower(args[i]), ".lua") {
				// lua script
				return func() error {
					setLuaArg(L, args[i:])
					_, err := runLua(it, L, args[i])
					if err != nil {
						return err
					} else {
						return io.EOF
					}
				}, nil
			} else {
				return func() error {
					// command script
					fd, fd_err := os.Open(args[i])
					if fd_err != nil {
						return fmt.Errorf("%s: %s\n", args[i], fd_err.Error())
					}
					scanner := bufio.NewScanner(fd)
					for scanner.Scan() {
						it.Interpret(scanner.Text())
					}
					fd.Close()
					return io.EOF
				}, nil
			}
		} else if arg1 == "-e" {
			i++
			if i >= len(args) {
				return nil, errors.New("-e: requires parameters")
			}
			return func() error {
				err := L.LoadString(args[i])
				if err != nil {
					return err
				}
				setLuaArg(L, args[i:])
				L.Call(0, 0)
				return io.EOF
			}, nil
		} else if arg1 == "--norc" {
			optionNorc = true
		} else if arg1 == "--lua-file" {
			i++
			if i >= len(args) {
				return nil, errors.New("--lua-file: requires parameters")
			}
			return func() error {
				setLuaArg(L, args[i:])
				_, err := runLua(it, L, args[i])
				if err != nil {
					return err
				} else {
					return io.EOF
				}
			}, nil
		}
	}
	return nil, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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

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

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

package config

import (
	"bytes"
	"io/ioutil"
	"os"
	"strings"
	"testing"

	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
)

type currentContextTest struct {
	startingConfig clientcmdapi.Config
	expectedError  string
}

func newFederalContextConfig() clientcmdapi.Config {
	return clientcmdapi.Config{
		CurrentContext: "federal-context",
	}
}

func TestCurrentContextWithSetContext(t *testing.T) {
	test := currentContextTest{
		startingConfig: newFederalContextConfig(),
		expectedError:  "",
	}

	test.run(t)
}

func TestCurrentContextWithUnsetContext(t *testing.T) {
	test := currentContextTest{
		startingConfig: *clientcmdapi.NewConfig(),
		expectedError:  "current-context is not set",
	}

	test.run(t)
}

func (test currentContextTest) run(t *testing.T) {
	fakeKubeFile, _ := ioutil.TempFile("", "")
	defer os.Remove(fakeKubeFile.Name())
	err := clientcmd.WriteToFile(test.startingConfig, fakeKubeFile.Name())
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	pathOptions := NewDefaultPathOptions()
	pathOptions.GlobalFile = fakeKubeFile.Name()
	options := CurrentContextOptions{
		ConfigAccess: pathOptions,
	}

	buf := bytes.NewBuffer([]byte{})
	err = RunCurrentContext(buf, []string{}, &options)
	if len(test.expectedError) != 0 {
		if err == nil {
			t.Errorf("Did not get %v", test.expectedError)
		} else {
			if !strings.Contains(err.Error(), test.expectedError) {
				t.Errorf("Expected %v, but got %v", test.expectedError, err)
			}
		}
		return
	}

	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
}
<commit_msg>clear env var check for unit test<commit_after>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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

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

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

package config

import (
	"bytes"
	"io/ioutil"
	"os"
	"strings"
	"testing"

	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
)

type currentContextTest struct {
	startingConfig clientcmdapi.Config
	expectedError  string
}

func newFederalContextConfig() clientcmdapi.Config {
	return clientcmdapi.Config{
		CurrentContext: "federal-context",
	}
}

func TestCurrentContextWithSetContext(t *testing.T) {
	test := currentContextTest{
		startingConfig: newFederalContextConfig(),
		expectedError:  "",
	}

	test.run(t)
}

func TestCurrentContextWithUnsetContext(t *testing.T) {
	test := currentContextTest{
		startingConfig: *clientcmdapi.NewConfig(),
		expectedError:  "current-context is not set",
	}

	test.run(t)
}

func (test currentContextTest) run(t *testing.T) {
	fakeKubeFile, _ := ioutil.TempFile("", "")
	defer os.Remove(fakeKubeFile.Name())
	err := clientcmd.WriteToFile(test.startingConfig, fakeKubeFile.Name())
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	pathOptions := NewDefaultPathOptions()
	pathOptions.GlobalFile = fakeKubeFile.Name()
	pathOptions.EnvVar = ""
	options := CurrentContextOptions{
		ConfigAccess: pathOptions,
	}

	buf := bytes.NewBuffer([]byte{})
	err = RunCurrentContext(buf, []string{}, &options)
	if len(test.expectedError) != 0 {
		if err == nil {
			t.Errorf("Did not get %v", test.expectedError)
		} else {
			if !strings.Contains(err.Error(), test.expectedError) {
				t.Errorf("Expected %v, but got %v", test.expectedError, err)
			}
		}
		return
	}

	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
}
<|endoftext|>


<commit_before>package lexer

import (
  "fmt"
  "strings"
  "unicode"
  "unicode/utf8"
)

type TokenType int

const EOF = -1

const (
  TokenError TokenType = iota
  TokenEOF

  TokenIdentifier

  TokenStringLiteral
  TokenIntegerLiteral
  TokenFloatLiteral
  TokenBooleanLiteral

  TokenQuote
  TokenQuasiquote
  TokenUnquote
  TokenUnquoteSplicing

  TokenOpenParen
  TokenCloseParen
  TokenOpenSquare
  TokenCloseSquare
)

type Token struct {
  Type  TokenType
  Value string
}

type stateFn func(*Lexer) stateFn

type Lexer struct {
  name   string
  input  string
  state  stateFn
  start  int
  pos    int
  width  int
  tokens chan Token
}

func NewLexer(name, input string) *Lexer {
  l := &Lexer{
    name:   name,
    input:  input,
    tokens: make(chan Token),
  }
  go l.run()
  return l
}

func (l *Lexer) NextToken() Token {
  return <-l.tokens
}

func (l *Lexer) run() {
  for l.state = lexWhiteSpace; l.state != nil; {
    l.state = l.state(l)
  }
  close(l.tokens)
}

func (l *Lexer) emit(t TokenType) {
  l.tokens <- Token{t, l.input[l.start:l.pos]}
  l.start = l.pos
}

func (l *Lexer) next() rune {
  if len(l.input) <= l.pos {
    l.width = 0
    return EOF
  }

  r, size := utf8.DecodeRuneInString(l.input[l.pos:])
  l.width = size
  l.pos += l.width

  return r
}

func (l *Lexer) backup() {
  l.pos -= l.width
}

func (l *Lexer) ignore() {
  l.start = l.pos
}

func (l *Lexer) peek() rune {
  r := l.next()
  l.backup()
  return r
}

func (l *Lexer) accept(valid string) bool {
  if strings.IndexRune(valid, l.next()) >= 0 {
    return true
  }
  l.backup()
  return false
}

func (l *Lexer) acceptRun(valid string) {
  for strings.IndexRune(valid, l.next()) >= 0 {
  }
  l.backup()
}

func (l *Lexer) errorf(format string, args ...interface{}) stateFn {
  l.tokens <- Token{TokenError, fmt.Sprintf(format, args...)}
  return nil
}

func lexWhiteSpace(l *Lexer) stateFn {
  for r := l.next(); r == ' ' || r == '\t' || r == '\n'; r = l.next() {
  }
  l.backup()
  l.ignore()

  switch r := l.next(); {
  case r == EOF:
    return lexEOF
  case r == ';':
    return lexComment
  case r == '(':
    return lexOpenParen
  case r == ')':
    return lexCloseParen
  case r == '"':
    return lexString
  case r == '\'':
    return lexQuote
  case r == '`':
    return lexQuasiquote
  case r == ',':
    return lexUnquote
  case r == '+' || r == '-' || ('0' <= r && r <= '9'):
    l.backup()
    return lexNumber
  case isAlphaNumeric(r):
    // begin with non-numberic character
    return lexIdentifier
  default:
    return l.errorf("Unexpected character: %q", r)
  }
}

func lexEOF(l *Lexer) stateFn {
  l.emit(TokenEOF)
  return nil
}

func lexQuote(l *Lexer) stateFn {
  l.emit(TokenQuote)
  return lexWhiteSpace
}

func lexQuasiquote(l *Lexer) stateFn {
  l.emit(TokenQuasiquote)
  return lexWhiteSpace
}

func lexUnquote(l *Lexer) stateFn {
  hasAt := l.accept("@")
  if !hasAt {
    l.emit(TokenUnquote)
  } else {
    l.emit(TokenUnquoteSplicing)
  }
  return lexWhiteSpace
}

func lexUnquoteSplicing(l *Lexer) stateFn {
  l.emit(TokenUnquoteSplicing)
  return lexWhiteSpace
}

func lexString(l *Lexer) stateFn {
  for r := l.next(); r != '"'; r = l.next() {
    if r == '\\' {
      r = l.next()
    }
    if r == EOF {
      return l.errorf("read: expected a closing `\"'")
    }
  }
  l.emit(TokenStringLiteral)
  return lexWhiteSpace
}

func lexOpenParen(l *Lexer) stateFn {
  l.emit(TokenOpenParen)
  return lexWhiteSpace
}

func lexCloseParen(l *Lexer) stateFn {
  l.emit(TokenCloseParen)
  return lexWhiteSpace
}

func lexIdentifier(l *Lexer) stateFn {
  for r := l.next(); isAlphaNumeric(r); r = l.next() {
  }
  l.backup()

  l.emit(TokenIdentifier)
  return lexWhiteSpace
}

func lexComment(l *Lexer) stateFn {
  for r := l.next(); r != '\n'; r = l.next() {
  }
  return lexWhiteSpace
}

func lexNumber(l *Lexer) stateFn {
  isFloat := false

  hasFlag := l.accept("+-")
  digits := "0123456789"
  if l.accept("0") && l.accept("xX") {
    digits = "0123456789abcdefABCDEF"
  }
  l.acceptRun(digits)

  if l.accept(".") {
    isFloat = true
    l.acceptRun(digits)
  }

  if l.accept("eE") {
    l.accept("+-")
    l.acceptRun("0123456789")
  }

  if r := l.peek(); isAlphaNumeric(r) {
    l.next()
    return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
  }

  if hasFlag && l.start+1 == l.pos {
    return lexIdentifier
  }

  if isFloat {
    l.emit(TokenFloatLiteral)
  } else {
    l.emit(TokenIntegerLiteral)
  }
  return lexWhiteSpace
}

func isAlphaNumeric(r rune) bool {
  if strings.IndexRune("!#$%&|*+-/:<=>?@^_~", r) >= 0 {
    return true
  }
  return r == '.' || unicode.IsLetter(r) || unicode.IsDigit(r)
}
<commit_msg>compatibility with Windows \r<commit_after>package lexer

import (
  "fmt"
  "strings"
  "unicode"
  "unicode/utf8"
)

type TokenType int

const EOF = -1

const (
  TokenError TokenType = iota
  TokenEOF

  TokenIdentifier

  TokenStringLiteral
  TokenIntegerLiteral
  TokenFloatLiteral
  TokenBooleanLiteral

  TokenQuote
  TokenQuasiquote
  TokenUnquote
  TokenUnquoteSplicing

  TokenOpenParen
  TokenCloseParen
  TokenOpenSquare
  TokenCloseSquare
)

type Token struct {
  Type  TokenType
  Value string
}

type stateFn func(*Lexer) stateFn

type Lexer struct {
  name   string
  input  string
  state  stateFn
  start  int
  pos    int
  width  int
  tokens chan Token
}

func NewLexer(name, input string) *Lexer {
  l := &Lexer{
    name:   name,
    input:  input,
    tokens: make(chan Token),
  }
  go l.run()
  return l
}

func (l *Lexer) NextToken() Token {
  return <-l.tokens
}

func (l *Lexer) run() {
  for l.state = lexWhiteSpace; l.state != nil; {
    l.state = l.state(l)
  }
  close(l.tokens)
}

func (l *Lexer) emit(t TokenType) {
  l.tokens <- Token{t, l.input[l.start:l.pos]}
  l.start = l.pos
}

func (l *Lexer) next() rune {
  if len(l.input) <= l.pos {
    l.width = 0
    return EOF
  }

  r, size := utf8.DecodeRuneInString(l.input[l.pos:])
  l.width = size
  l.pos += l.width

  return r
}

func (l *Lexer) backup() {
  l.pos -= l.width
}

func (l *Lexer) ignore() {
  l.start = l.pos
}

func (l *Lexer) peek() rune {
  r := l.next()
  l.backup()
  return r
}

func (l *Lexer) accept(valid string) bool {
  if strings.IndexRune(valid, l.next()) >= 0 {
    return true
  }
  l.backup()
  return false
}

func (l *Lexer) acceptRun(valid string) {
  for strings.IndexRune(valid, l.next()) >= 0 {
  }
  l.backup()
}

func (l *Lexer) errorf(format string, args ...interface{}) stateFn {
  l.tokens <- Token{TokenError, fmt.Sprintf(format, args...)}
  return nil
}

func lexWhiteSpace(l *Lexer) stateFn {
  for r := l.next(); r == ' ' || r == '\t' || r == '\n' || r == '\r'; r = l.next() {
  }
  l.backup()
  l.ignore()

  switch r := l.next(); {
  case r == EOF:
    return lexEOF
  case r == ';':
    return lexComment
  case r == '(':
    return lexOpenParen
  case r == ')':
    return lexCloseParen
  case r == '"':
    return lexString
  case r == '\'':
    return lexQuote
  case r == '`':
    return lexQuasiquote
  case r == ',':
    return lexUnquote
  case r == '+' || r == '-' || ('0' <= r && r <= '9'):
    l.backup()
    return lexNumber
  case isAlphaNumeric(r):
    // begin with non-numberic character
    return lexIdentifier
  default:
    return l.errorf("Unexpected character: %q", r)
  }
}

func lexEOF(l *Lexer) stateFn {
  l.emit(TokenEOF)
  return nil
}

func lexQuote(l *Lexer) stateFn {
  l.emit(TokenQuote)
  return lexWhiteSpace
}

func lexQuasiquote(l *Lexer) stateFn {
  l.emit(TokenQuasiquote)
  return lexWhiteSpace
}

func lexUnquote(l *Lexer) stateFn {
  hasAt := l.accept("@")
  if !hasAt {
    l.emit(TokenUnquote)
  } else {
    l.emit(TokenUnquoteSplicing)
  }
  return lexWhiteSpace
}

func lexUnquoteSplicing(l *Lexer) stateFn {
  l.emit(TokenUnquoteSplicing)
  return lexWhiteSpace
}

func lexString(l *Lexer) stateFn {
  for r := l.next(); r != '"'; r = l.next() {
    if r == '\\' {
      r = l.next()
    }
    if r == EOF {
      return l.errorf("read: expected a closing `\"'")
    }
  }
  l.emit(TokenStringLiteral)
  return lexWhiteSpace
}

func lexOpenParen(l *Lexer) stateFn {
  l.emit(TokenOpenParen)
  return lexWhiteSpace
}

func lexCloseParen(l *Lexer) stateFn {
  l.emit(TokenCloseParen)
  return lexWhiteSpace
}

func lexIdentifier(l *Lexer) stateFn {
  for r := l.next(); isAlphaNumeric(r); r = l.next() {
  }
  l.backup()

  l.emit(TokenIdentifier)
  return lexWhiteSpace
}

func lexComment(l *Lexer) stateFn {
  for r := l.next(); r != '\n'; r = l.next() {
  }
  return lexWhiteSpace
}

func lexNumber(l *Lexer) stateFn {
  isFloat := false

  hasFlag := l.accept("+-")
  digits := "0123456789"
  if l.accept("0") && l.accept("xX") {
    digits = "0123456789abcdefABCDEF"
  }
  l.acceptRun(digits)

  if l.accept(".") {
    isFloat = true
    l.acceptRun(digits)
  }

  if l.accept("eE") {
    l.accept("+-")
    l.acceptRun("0123456789")
  }

  if r := l.peek(); isAlphaNumeric(r) {
    l.next()
    return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
  }

  if hasFlag && l.start+1 == l.pos {
    return lexIdentifier
  }

  if isFloat {
    l.emit(TokenFloatLiteral)
  } else {
    l.emit(TokenIntegerLiteral)
  }
  return lexWhiteSpace
}

func isAlphaNumeric(r rune) bool {
  if strings.IndexRune("!#$%&|*+-/:<=>?@^_~", r) >= 0 {
    return true
  }
  return r == '.' || unicode.IsLetter(r) || unicode.IsDigit(r)
}
<|endoftext|>


<commit_before>// Copyright 2019 The OpenPitrix Authors. All rights reserved.
// Use of this source code is governed by a Apache license
// that can be found in the LICENSE file.

package service_config

import (
	"context"
	"fmt"

	nfpb "openpitrix.io/notification/pkg/pb"
	nfclient "openpitrix.io/openpitrix/pkg/client/notification"
	"openpitrix.io/openpitrix/pkg/config"
	"openpitrix.io/openpitrix/pkg/constants"
	"openpitrix.io/openpitrix/pkg/gerr"
	"openpitrix.io/openpitrix/pkg/pb"
	"openpitrix.io/openpitrix/pkg/pi"
	"openpitrix.io/openpitrix/pkg/util/pbutil"
)

func OpToNfConfig(opConfig *pb.NotificationConfig) *nfpb.ServiceConfig {
	return &nfpb.ServiceConfig{
		EmailServiceConfig: &nfpb.EmailServiceConfig{
			Protocol:      opConfig.EmailServiceConfig.Protocol,
			EmailHost:     opConfig.EmailServiceConfig.EmailHost,
			Port:          opConfig.EmailServiceConfig.Port,
			DisplaySender: opConfig.EmailServiceConfig.DisplaySender,
			Email:         opConfig.EmailServiceConfig.Email,
			Password:      opConfig.EmailServiceConfig.Password,
			SslEnable:     opConfig.EmailServiceConfig.SslEnable,
		},
	}
}

func NfToOpConfig(nfConfig *nfpb.ServiceConfig) *pb.NotificationConfig {
	return &pb.NotificationConfig{
		EmailServiceConfig: &pb.EmailServiceConfig{
			Protocol:      nfConfig.EmailServiceConfig.Protocol,
			EmailHost:     nfConfig.EmailServiceConfig.EmailHost,
			Port:          nfConfig.EmailServiceConfig.Port,
			DisplaySender: nfConfig.EmailServiceConfig.DisplaySender,
			Email:         nfConfig.EmailServiceConfig.Email,
			Password:      nfConfig.EmailServiceConfig.Password,
			SslEnable:     nfConfig.EmailServiceConfig.SslEnable,
		},
	}
}

func (p *Server) SetServiceConfig(ctx context.Context, req *pb.SetServiceConfigRequest) (*pb.SetServiceConfigResponse, error) {
	if req.NotificationConfig != nil && req.NotificationConfig.EmailServiceConfig != nil {
		nfClient, err := nfclient.NewClient()
		if err != nil {
			return nil, gerr.NewWithDetail(ctx, gerr.Internal, err, gerr.ErrorSetNotificationConfig)
		}
		response, err := nfClient.SetServiceConfig(ctx, OpToNfConfig(req.NotificationConfig))
		if err != nil {
			return nil, gerr.NewWithDetail(ctx, gerr.Internal, err, gerr.ErrorSetNotificationConfig)
		}
		if !response.GetIsSucc().GetValue() {
			return nil, gerr.NewWithDetail(ctx, gerr.Internal, err, gerr.ErrorSetNotificationConfig)
		}
	} else if req.RuntimeConfig != nil {
		for _, config := range req.RuntimeConfig.ConfigSet {
			name := config.GetName().GetValue()
			enable := config.GetEnable().GetValue()
			runtimeProviderConfig, isExist := pi.Global().GlobalConfig().Runtime[name]
			if !isExist {
				return nil, gerr.New(ctx, gerr.InvalidArgument, gerr.ErrorUnsupportedRuntimeProvider, name)
			}
			runtimeProviderConfig.Enable = enable
		}
		err := pi.Global().SetGlobalCfg(ctx)
		if err != nil {
			return nil, gerr.New(ctx, gerr.Internal, gerr.ErrorSetServiceConfig)
		}
	} else if req.BasicConfig != nil {
		basicCfg := config.BasicConfig{
			PlatformName: req.BasicConfig.GetPlatformName().GetValue(),
			PlatformUrl:  req.BasicConfig.GetPlatformUrl().GetValue(),
		}

		globalCfg := pi.Global().GlobalConfig()
		globalCfg.BasicCfg = basicCfg

		err := pi.Global().SetGlobalCfg(ctx)
		if err != nil {
			return nil, gerr.New(ctx, gerr.Internal, gerr.ErrorSetServiceConfig)
		}

	} else {
		err := fmt.Errorf("need service config to set")
		return nil, gerr.NewWithDetail(ctx, gerr.InvalidArgument, err, gerr.ErrorSetServiceConfig)
	}

	return &pb.SetServiceConfigResponse{
		IsSucc: pbutil.ToProtoBool(true),
	}, nil
}

func (p *Server) GetServiceConfig(ctx context.Context, req *pb.GetServiceConfigRequest) (*pb.GetServiceConfigResponse, error) {
	if len(req.ServiceType) == 0 {
		req.ServiceType = constants.ServiceTypes
	}

	serviceConfigResponse := new(pb.GetServiceConfigResponse)
	for _, serviceType := range req.GetServiceType() {
		switch serviceType {
		case constants.ServiceTypeNotification:
			nfClient, err := nfclient.NewClient()
			if err != nil {
				return nil, gerr.NewWithDetail(ctx, gerr.Internal, err, gerr.ErrorGetNotificationConfig)
			}
			// empty means all config
			response, err := nfClient.GetServiceConfig(ctx, &nfpb.GetServiceConfigRequest{
				ServiceType: []string{},
			})
			if err != nil {
				return nil, gerr.NewWithDetail(ctx, gerr.Internal, err, gerr.ErrorGetNotificationConfig)
			}
			serviceConfigResponse.NotificationConfig = NfToOpConfig(response)
		case constants.ServiceTypeRuntime:
			var configs []*pb.RuntimeItemConfig
			for name, runtimeProviderConfig := range pi.Global().GlobalConfig().Runtime {
				configs = append(configs, &pb.RuntimeItemConfig{
					Name:   pbutil.ToProtoString(name),
					Enable: pbutil.ToProtoBool(runtimeProviderConfig.Enable),
				})
			}
			serviceConfigResponse.RuntimeConfig = &pb.RuntimeConfig{
				ConfigSet: configs,
			}
		case constants.ServiceTypeBasicConfig:

			basicCfg := pi.Global().GlobalConfig().BasicCfg
			serviceConfigResponse.BasicConfig = &pb.BasicConfig{
				PlatformName: pbutil.ToProtoString(basicCfg.PlatformName),
				PlatformUrl:  pbutil.ToProtoString(basicCfg.PlatformUrl),
			}
		}
	}
	return serviceConfigResponse, nil
}

func (p *Server) ValidateEmailService(ctx context.Context, req *pb.ValidateEmailServiceRequest) (*pb.ValidateEmailServiceResponse, error) {
	nfClient, err := nfclient.NewClient()
	if err != nil {
		return nil, gerr.NewWithDetail(ctx, gerr.Internal, err, gerr.ErrorValidateEmailService)
	}
	reqServiceCfg := &nfpb.ServiceConfig{
		EmailServiceConfig: &nfpb.EmailServiceConfig{
			Protocol:      req.EmailServiceConfig.Protocol,
			EmailHost:     req.EmailServiceConfig.EmailHost,
			Port:          req.EmailServiceConfig.Port,
			DisplaySender: req.EmailServiceConfig.DisplaySender,
			Email:         req.EmailServiceConfig.Email,
			Password:      req.EmailServiceConfig.Password,
			SslEnable:     req.EmailServiceConfig.SslEnable,
		},
	}
	response, err := nfClient.ValidateEmailService(ctx, reqServiceCfg)
	if err != nil {
		return nil, gerr.NewWithDetail(ctx, gerr.Internal, err, gerr.ErrorValidateEmailService)
	}
	if !response.GetIsSucc().GetValue() {
		return nil, gerr.New(ctx, gerr.Internal, gerr.ErrorValidateEmailService)
	}
	return &pb.ValidateEmailServiceResponse{
		IsSucc: pbutil.ToProtoBool(true),
	}, nil
}
<commit_msg>fix validate email config issue. (#909)<commit_after>// Copyright 2019 The OpenPitrix Authors. All rights reserved.
// Use of this source code is governed by a Apache license
// that can be found in the LICENSE file.

package service_config

import (
	"context"
	"fmt"

	nfpb "openpitrix.io/notification/pkg/pb"
	nfclient "openpitrix.io/openpitrix/pkg/client/notification"
	"openpitrix.io/openpitrix/pkg/config"
	"openpitrix.io/openpitrix/pkg/constants"
	"openpitrix.io/openpitrix/pkg/gerr"
	"openpitrix.io/openpitrix/pkg/pb"
	"openpitrix.io/openpitrix/pkg/pi"
	"openpitrix.io/openpitrix/pkg/util/pbutil"
)

func OpToNfConfig(opConfig *pb.NotificationConfig) *nfpb.ServiceConfig {
	return &nfpb.ServiceConfig{
		EmailServiceConfig: &nfpb.EmailServiceConfig{
			Protocol:      opConfig.EmailServiceConfig.Protocol,
			EmailHost:     opConfig.EmailServiceConfig.EmailHost,
			Port:          opConfig.EmailServiceConfig.Port,
			DisplaySender: opConfig.EmailServiceConfig.DisplaySender,
			Email:         opConfig.EmailServiceConfig.Email,
			Password:      opConfig.EmailServiceConfig.Password,
			SslEnable:     opConfig.EmailServiceConfig.SslEnable,
		},
	}
}

func NfToOpConfig(nfConfig *nfpb.ServiceConfig) *pb.NotificationConfig {
	return &pb.NotificationConfig{
		EmailServiceConfig: &pb.EmailServiceConfig{
			Protocol:      nfConfig.EmailServiceConfig.Protocol,
			EmailHost:     nfConfig.EmailServiceConfig.EmailHost,
			Port:          nfConfig.EmailServiceConfig.Port,
			DisplaySender: nfConfig.EmailServiceConfig.DisplaySender,
			Email:         nfConfig.EmailServiceConfig.Email,
			Password:      nfConfig.EmailServiceConfig.Password,
			SslEnable:     nfConfig.EmailServiceConfig.SslEnable,
		},
	}
}

func (p *Server) SetServiceConfig(ctx context.Context, req *pb.SetServiceConfigRequest) (*pb.SetServiceConfigResponse, error) {
	if req.NotificationConfig != nil && req.NotificationConfig.EmailServiceConfig != nil {
		nfClient, err := nfclient.NewClient()
		if err != nil {
			return nil, gerr.NewWithDetail(ctx, gerr.Internal, err, gerr.ErrorSetNotificationConfig)
		}
		response, err := nfClient.SetServiceConfig(ctx, OpToNfConfig(req.NotificationConfig))
		if err != nil {
			return nil, gerr.NewWithDetail(ctx, gerr.Internal, err, gerr.ErrorSetNotificationConfig)
		}
		if !response.GetIsSucc().GetValue() {
			return nil, gerr.NewWithDetail(ctx, gerr.Internal, err, gerr.ErrorSetNotificationConfig)
		}
	} else if req.RuntimeConfig != nil {
		for _, config := range req.RuntimeConfig.ConfigSet {
			name := config.GetName().GetValue()
			enable := config.GetEnable().GetValue()
			runtimeProviderConfig, isExist := pi.Global().GlobalConfig().Runtime[name]
			if !isExist {
				return nil, gerr.New(ctx, gerr.InvalidArgument, gerr.ErrorUnsupportedRuntimeProvider, name)
			}
			runtimeProviderConfig.Enable = enable
		}
		err := pi.Global().SetGlobalCfg(ctx)
		if err != nil {
			return nil, gerr.New(ctx, gerr.Internal, gerr.ErrorSetServiceConfig)
		}
	} else if req.BasicConfig != nil {
		basicCfg := config.BasicConfig{
			PlatformName: req.BasicConfig.GetPlatformName().GetValue(),
			PlatformUrl:  req.BasicConfig.GetPlatformUrl().GetValue(),
		}

		globalCfg := pi.Global().GlobalConfig()
		globalCfg.BasicCfg = basicCfg

		err := pi.Global().SetGlobalCfg(ctx)
		if err != nil {
			return nil, gerr.New(ctx, gerr.Internal, gerr.ErrorSetServiceConfig)
		}

	} else {
		err := fmt.Errorf("need service config to set")
		return nil, gerr.NewWithDetail(ctx, gerr.InvalidArgument, err, gerr.ErrorSetServiceConfig)
	}

	return &pb.SetServiceConfigResponse{
		IsSucc: pbutil.ToProtoBool(true),
	}, nil
}

func (p *Server) GetServiceConfig(ctx context.Context, req *pb.GetServiceConfigRequest) (*pb.GetServiceConfigResponse, error) {
	if len(req.ServiceType) == 0 {
		req.ServiceType = constants.ServiceTypes
	}

	serviceConfigResponse := new(pb.GetServiceConfigResponse)
	for _, serviceType := range req.GetServiceType() {
		switch serviceType {
		case constants.ServiceTypeNotification:
			nfClient, err := nfclient.NewClient()
			if err != nil {
				return nil, gerr.NewWithDetail(ctx, gerr.Internal, err, gerr.ErrorGetNotificationConfig)
			}
			// empty means all config
			response, err := nfClient.GetServiceConfig(ctx, &nfpb.GetServiceConfigRequest{
				ServiceType: []string{},
			})
			if err != nil {
				return nil, gerr.NewWithDetail(ctx, gerr.Internal, err, gerr.ErrorGetNotificationConfig)
			}
			serviceConfigResponse.NotificationConfig = NfToOpConfig(response)
		case constants.ServiceTypeRuntime:
			var configs []*pb.RuntimeItemConfig
			for name, runtimeProviderConfig := range pi.Global().GlobalConfig().Runtime {
				configs = append(configs, &pb.RuntimeItemConfig{
					Name:   pbutil.ToProtoString(name),
					Enable: pbutil.ToProtoBool(runtimeProviderConfig.Enable),
				})
			}
			serviceConfigResponse.RuntimeConfig = &pb.RuntimeConfig{
				ConfigSet: configs,
			}
		case constants.ServiceTypeBasicConfig:

			basicCfg := pi.Global().GlobalConfig().BasicCfg
			serviceConfigResponse.BasicConfig = &pb.BasicConfig{
				PlatformName: pbutil.ToProtoString(basicCfg.PlatformName),
				PlatformUrl:  pbutil.ToProtoString(basicCfg.PlatformUrl),
			}
		}
	}
	return serviceConfigResponse, nil
}

func (p *Server) ValidateEmailService(ctx context.Context, req *pb.ValidateEmailServiceRequest) (*pb.ValidateEmailServiceResponse, error) {
	nfClient, err := nfclient.NewClient()
	if err != nil {
		return nil, gerr.NewWithDetail(ctx, gerr.Internal, err, gerr.ErrorValidateEmailService)
	}
	if req.EmailServiceConfig == nil {
		return nil, gerr.New(ctx, gerr.InvalidArgument, gerr.ErrorValidateEmailService)
	}
	reqServiceCfg := &nfpb.ServiceConfig{
		EmailServiceConfig: &nfpb.EmailServiceConfig{
			Protocol:      req.EmailServiceConfig.Protocol,
			EmailHost:     req.EmailServiceConfig.EmailHost,
			Port:          req.EmailServiceConfig.Port,
			DisplaySender: req.EmailServiceConfig.DisplaySender,
			Email:         req.EmailServiceConfig.Email,
			Password:      req.EmailServiceConfig.Password,
			SslEnable:     req.EmailServiceConfig.SslEnable,
		},
	}
	response, err := nfClient.ValidateEmailService(ctx, reqServiceCfg)
	if err != nil {
		return nil, gerr.NewWithDetail(ctx, gerr.Internal, err, gerr.ErrorValidateEmailService)
	}
	if !response.GetIsSucc().GetValue() {
		return nil, gerr.New(ctx, gerr.Internal, gerr.ErrorValidateEmailService)
	}
	return &pb.ValidateEmailServiceResponse{
		IsSucc: pbutil.ToProtoBool(true),
	}, nil
}
<|endoftext|>