<commit_before>package main

import (
        "github.com/vonwenm/goserial"
        "log"
        "time"
)

func main() {

        log.Print("CONNECTING")

        c := &serial.Config{Name: "COM4", Baud: 9600 }
            s, err := serial.OpenPort(c)
            if err != nil {
                    log.Fatal(err)
        }

        log.Print("CONNECTED")

        test := 10

        for (test == 10) {

        //======================

                var msg01 string  = "m1 on"

		n, err := s.Write([]byte( msg01 ))
		if err != nil {
			log.Fatal(err)
		}

                log.Print( "SND:  ", msg01 )

		buf := make([]byte, 128)
		n, err = s.Read(buf)
		if err != nil {
			log.Fatal(err)
		}

	        sx0 := string( buf[:n] )

	        log.Print("REC: ", sx0 )

       //==================

        	time.Sleep(time.Second * 6 )

       //==================

                var msg02 string  = "m1 off"

	        n1, err1 := s.Write([]byte( msg02  ))
	        if err1 != nil {
	                log.Fatal(err1)
	        }

                log.Print( "SND:  ", msg02 )

	        buf1 := make([]byte, 128)
	        n1, err1 = s.Read(buf1)
	        if err1 != nil {
	                log.Fatal(err1)
	        }

	        sx1 := string( buf1[:n1] )

	        log.Print("REC: ", sx1 )

       //==================

       		time.Sleep(time.Second * 6  )

        }
}<commit_msg>init2<commit_after>package main

import (
        "github.com/vonwenm/goserial"
        "log"
        "time"
)

func main() {

        log.Print("CONNECTING")

        c := &serial.Config{Name: "/dev/ttyUSB0", Baud: 9600 }
            s, err := serial.OpenPort(c)
            if err != nil {
                    log.Fatal(err)
        }

        log.Print("CONNECTED")

        test := 10

        for (test == 10) {

        //======================

                var msg01 string  = "m1 on"

		n, err := s.Write([]byte( msg01 ))
		if err != nil {
			log.Fatal(err)
		}

                log.Print( "SND:  ", msg01 )

		buf := make([]byte, 128)
		n, err = s.Read(buf)
		if err != nil {
			log.Fatal(err)
		}

	        sx0 := string( buf[:n] )

	        log.Print("REC: ", sx0 )

       //==================

        	time.Sleep(time.Second * 6 )

       //==================

                var msg02 string  = "m1 off"

	        n1, err1 := s.Write([]byte( msg02  ))
	        if err1 != nil {
	                log.Fatal(err1)
	        }

                log.Print( "SND:  ", msg02 )

	        buf1 := make([]byte, 128)
	        n1, err1 = s.Read(buf1)
	        if err1 != nil {
	                log.Fatal(err1)
	        }

	        sx1 := string( buf1[:n1] )

	        log.Print("REC: ", sx1 )

       //==================

       		time.Sleep(time.Second * 6  )

        }
}
<|endoftext|>


<commit_before>package inet

import (
	"context"
	"fmt"
	"net"
	"strings"
	"time"
)

const DefaultIfName = "loki0"
const DefaultPort = "0"
const DefaultDNSAddr = "127.0.0.1:1153"

type Session struct {
	localIP   net.IP
	localAddr string
	name      string
	port      string
	serv      net.Listener
	packet    net.PacketConn
	resolver  net.Resolver
	dialer    net.Dialer
}

func NewSession(ifname, port, dns string) (s *Session, err error) {
	var netif *net.Interface
	netif, err = net.InterfaceByName(ifname)
	if err != nil {
		return
	}
	var ifaddrs []net.Addr
	ifaddrs, err = netif.Addrs()
	if err != nil {
		return
	}
	if len(ifaddrs) == 0 {
		err = fmt.Errorf("%s has no addresses? duh fug yo...", ifname)
		return
	}
	var localIP net.IP
	localIP, _, err = net.ParseCIDR(ifaddrs[0].String())
	if err != nil {
		return
	}
	var laddr *net.TCPAddr
	laddr, err = net.ResolveTCPAddr("tcp", net.JoinHostPort(localIP.String(), "0"))
	if err != nil {
		return
	}
	ss := &Session{
		port:      port,
		localIP:   localIP,
		localAddr: net.JoinHostPort(localIP.String(), port),
		resolver: net.Resolver{
			Dial: func(ctx context.Context, n, a string) (net.Conn, error) {
				var d net.Dialer
				return d.DialContext(ctx, "udp", dns)
			},
		},
		dialer: net.Dialer{
			LocalAddr: laddr,
		},
	}
	var names []string
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()
	names, err = ss.resolver.LookupAddr(ctx, ss.localIP.String())
	if err != nil {
		return
	}
	if len(names) == 0 {
		err = fmt.Errorf("we have no rdns record for %s", ifname)
		return
	}
	ss.name = strings.TrimSuffix(names[0], ".")
	s = ss
	s.dialer.Resolver = &s.resolver
	return
}

func (s *Session) LocalName() string {
	return s.name
}

func (s *Session) Dial(n, a string) (net.Conn, error) {
	if s.dialer.LocalAddr == nil {
		return nil, fmt.Errorf("connection not ready")
	}
	c, err := s.dialer.Dial(n, a)
	if err != nil {
		return nil, err
	}
	return s.wrapConn(c)
}

func (s *Session) wrapConn(c net.Conn) (*Conn, error) {
	raddr := c.RemoteAddr()
	h, port, err := net.SplitHostPort(raddr.String())
	if err != nil {
		c.Close()
		return nil, err
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
	defer cancel()
	names, err := s.resolver.LookupAddr(ctx, h)
	if err != nil {
		c.Close()
		return nil, err
	}
	return &Conn{
		c: c,
		laddr: &Addr{
			name: s.name,
			port: s.port,
		},
		raddr: &Addr{
			name: strings.TrimSuffix(names[0], "."),
			port: port,
		},
	}, nil
}

type Listener struct {
	l     net.Listener
	laddr *Addr
}

func (l *Listener) Addr() net.Addr {
	return l.laddr
}

func (l *Listener) Close() error {
	return l.l.Close()
}

func (l *Listener) Accept() (net.Conn, error) {
	return l.l.Accept()
}

func NewAddr(n, p string) *Addr {
	return &Addr{
		name: n,
		port: p,
	}
}

type Addr struct {
	name string
	port string
}

func (a *Addr) Network() string {
	return "tcp"
}

func (a *Addr) String() string {
	return net.JoinHostPort(a.name, a.port)
}

type Conn struct {
	c     net.Conn
	laddr *Addr
	raddr *Addr
}

// implements net.Conn
func (c *Conn) Read(d []byte) (n int, err error) {
	n, err = c.c.Read(d)
	return
}

// implements net.Conn
func (c *Conn) Write(d []byte) (n int, err error) {
	n, err = c.c.Write(d)
	return
}

// implements net.Conn
func (c *Conn) Close() error {
	return c.c.Close()
}

// implements net.Conn
func (c *Conn) LocalAddr() net.Addr {
	return c.laddr
}

// implements net.Conn
func (c *Conn) RemoteAddr() net.Addr {
	return c.raddr
}

// implements net.Conn
func (c *Conn) SetDeadline(t time.Time) error {
	return c.c.SetDeadline(t)
}

// implements net.Conn
func (c *Conn) SetReadDeadline(t time.Time) error {
	return c.c.SetReadDeadline(t)
}

// implements net.Conn
func (c *Conn) SetWriteDeadline(t time.Time) error {
	return c.c.SetWriteDeadline(t)
}

func (s *Session) Accept() (net.Conn, error) {
	c, err := s.serv.Accept()
	if err != nil {
		return nil, err
	}
	return s.wrapConn(c)
}

func (s *Session) Open() error {
	l, err := net.Listen("tcp", s.localAddr)
	if err != nil {
		return err
	}
	_, port, err := net.SplitHostPort(l.Addr().String())
	if err != nil {
		return err
	}
	s.serv = &Listener{
		l: l,
		laddr: &Addr{
			name: s.name,
			port: port,
		},
	}
	return nil
}

func (s *Session) ReadFrom(d []byte) (n int, from net.Addr, err error) {
	return
}

func (s *Session) WriteTo(d []byte, to net.Addr) (n int, err error) {
	return
}

func (s *Session) Close() error {
	return s.serv.Close()
}

func (s *Session) Addr() net.Addr {
	if s.serv == nil {
		return nil
	}
	return s.serv.Addr()
}

func (s *Session) Lookup(name, port string) (addr net.Addr, err error) {
	var ips []net.IPAddr
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()
	ips, err = s.resolver.LookupIPAddr(ctx, name)
	if err == nil {
		for _, ip := range ips {
			tcpaddr := &net.TCPAddr{
				IP: ip.IP,
			}
			tcpaddr.Port, err = net.LookupPort(tcpaddr.Network(), port)
			if err == nil {
				addr = tcpaddr
				return
			}
		}
	}
	return
}
<commit_msg>tweak defaults<commit_after>package inet

import (
	"context"
	"fmt"
	"net"
	"strings"
	"time"
)

const DefaultIfName = "lokitun0"
const DefaultPort = "0"
const DefaultDNSAddr = "127.0.0.1:53"

type Session struct {
	localIP   net.IP
	localAddr string
	name      string
	port      string
	serv      net.Listener
	packet    net.PacketConn
	resolver  net.Resolver
	dialer    net.Dialer
}

func NewSession(ifname, port, dns string) (s *Session, err error) {
	var netif *net.Interface
	netif, err = net.InterfaceByName(ifname)
	if err != nil {
		return
	}
	var ifaddrs []net.Addr
	ifaddrs, err = netif.Addrs()
	if err != nil {
		return
	}
	if len(ifaddrs) == 0 {
		err = fmt.Errorf("%s has no addresses? duh fug yo...", ifname)
		return
	}
	var localIP net.IP
	localIP, _, err = net.ParseCIDR(ifaddrs[0].String())
	if err != nil {
		return
	}
	var laddr *net.TCPAddr
	laddr, err = net.ResolveTCPAddr("tcp", net.JoinHostPort(localIP.String(), "0"))
	if err != nil {
		return
	}
	ss := &Session{
		port:      port,
		localIP:   localIP,
		localAddr: net.JoinHostPort(localIP.String(), port),
		resolver: net.Resolver{
			Dial: func(ctx context.Context, n, a string) (net.Conn, error) {
				var d net.Dialer
				return d.DialContext(ctx, "udp", dns)
			},
		},
		dialer: net.Dialer{
			LocalAddr: laddr,
		},
	}
	var names []string
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()
	names, err = ss.resolver.LookupAddr(ctx, ss.localIP.String())
	if err != nil {
		return
	}
	if len(names) == 0 {
		err = fmt.Errorf("we have no rdns record for %s", ifname)
		return
	}
	ss.name = strings.TrimSuffix(names[0], ".")
	s = ss
	s.dialer.Resolver = &s.resolver
	return
}

func (s *Session) LocalName() string {
	return s.name
}

func (s *Session) Dial(n, a string) (net.Conn, error) {
	if s.dialer.LocalAddr == nil {
		return nil, fmt.Errorf("connection not ready")
	}
	c, err := s.dialer.Dial(n, a)
	if err != nil {
		return nil, err
	}
	return s.wrapConn(c)
}

func (s *Session) wrapConn(c net.Conn) (*Conn, error) {
	raddr := c.RemoteAddr()
	h, port, err := net.SplitHostPort(raddr.String())
	if err != nil {
		c.Close()
		return nil, err
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
	defer cancel()
	names, err := s.resolver.LookupAddr(ctx, h)
	if err != nil {
		c.Close()
		return nil, err
	}
	return &Conn{
		c: c,
		laddr: &Addr{
			name: s.name,
			port: s.port,
		},
		raddr: &Addr{
			name: strings.TrimSuffix(names[0], "."),
			port: port,
		},
	}, nil
}

type Listener struct {
	l     net.Listener
	laddr *Addr
}

func (l *Listener) Addr() net.Addr {
	return l.laddr
}

func (l *Listener) Close() error {
	return l.l.Close()
}

func (l *Listener) Accept() (net.Conn, error) {
	return l.l.Accept()
}

func NewAddr(n, p string) *Addr {
	return &Addr{
		name: n,
		port: p,
	}
}

type Addr struct {
	name string
	port string
}

func (a *Addr) Network() string {
	return "tcp"
}

func (a *Addr) String() string {
	return net.JoinHostPort(a.name, a.port)
}

type Conn struct {
	c     net.Conn
	laddr *Addr
	raddr *Addr
}

// implements net.Conn
func (c *Conn) Read(d []byte) (n int, err error) {
	n, err = c.c.Read(d)
	return
}

// implements net.Conn
func (c *Conn) Write(d []byte) (n int, err error) {
	n, err = c.c.Write(d)
	return
}

// implements net.Conn
func (c *Conn) Close() error {
	return c.c.Close()
}

// implements net.Conn
func (c *Conn) LocalAddr() net.Addr {
	return c.laddr
}

// implements net.Conn
func (c *Conn) RemoteAddr() net.Addr {
	return c.raddr
}

// implements net.Conn
func (c *Conn) SetDeadline(t time.Time) error {
	return c.c.SetDeadline(t)
}

// implements net.Conn
func (c *Conn) SetReadDeadline(t time.Time) error {
	return c.c.SetReadDeadline(t)
}

// implements net.Conn
func (c *Conn) SetWriteDeadline(t time.Time) error {
	return c.c.SetWriteDeadline(t)
}

func (s *Session) Accept() (net.Conn, error) {
	c, err := s.serv.Accept()
	if err != nil {
		return nil, err
	}
	return s.wrapConn(c)
}

func (s *Session) Open() error {
	l, err := net.Listen("tcp", s.localAddr)
	if err != nil {
		return err
	}
	_, port, err := net.SplitHostPort(l.Addr().String())
	if err != nil {
		return err
	}
	s.serv = &Listener{
		l: l,
		laddr: &Addr{
			name: s.name,
			port: port,
		},
	}
	return nil
}

func (s *Session) ReadFrom(d []byte) (n int, from net.Addr, err error) {
	return
}

func (s *Session) WriteTo(d []byte, to net.Addr) (n int, err error) {
	return
}

func (s *Session) Close() error {
	return s.serv.Close()
}

func (s *Session) Addr() net.Addr {
	if s.serv == nil {
		return nil
	}
	return s.serv.Addr()
}

func (s *Session) Lookup(name, port string) (addr net.Addr, err error) {
	var ips []net.IPAddr
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()
	ips, err = s.resolver.LookupIPAddr(ctx, name)
	if err == nil {
		for _, ip := range ips {
			tcpaddr := &net.TCPAddr{
				IP: ip.IP,
			}
			tcpaddr.Port, err = net.LookupPort(tcpaddr.Network(), port)
			if err == nil {
				addr = tcpaddr
				return
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>package prompt

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"text/template"

	"github.com/josledp/goprompt/prompt/plugin"
	"github.com/josledp/termcolor"
)

//Prompt is the struct with the prompt options/config
type Prompt struct {
	options map[string]interface{}
	cache   *Cache
	plugins map[string]Plugin
	format  func(string, ...termcolor.Mode) string

	debug   bool
	tmpMode []termcolor.Mode
}

//Plugin is the interface all the plugins MUST implement
type Plugin interface {
	Name() string
	Help() (description string, options map[string]string)
	Load(pr plugin.Prompter) error
	Get(format func(string, ...termcolor.Mode) string) (string, []termcolor.Mode)
}

//New returns a new promp
func New(options map[string]interface{}, color, debug bool) Prompt {
	c, err := newCache()
	if err != nil {
		log.Printf("unable to initializa cache: %v", err)
	}
	// map plugin by name
	mPlugins := make(map[string]Plugin)
	for _, p := range availablePlugins {
		mPlugins[p.Name()] = p
	}
	var format func(string, ...termcolor.Mode) string

	if color {
		shell := detectShell()
		switch shell {
		case "bash":
			format = termcolor.EscapedFormat
		case "fish":
			format = termcolor.Format
		case "zsh":
			format = termcolor.Format

		default:
			//Defaut failsafe
			format = func(s string, modes ...termcolor.Mode) string { return s }
		}
	} else {
		format = func(s string, modes ...termcolor.Mode) string { return s }
	}

	return Prompt{
		options: options,
		cache:   c,
		plugins: mPlugins,
		format:  format,
		debug:   debug,
		tmpMode: nil,
	}
}

//GetOption returns the option value for key
func (pr Prompt) GetOption(key string) (interface{}, bool) {
	value, ok := pr.options[key]
	return value, ok
}

//GetCache recovers a value from cache
func (pr Prompt) GetCache(key string) (interface{}, bool) {
	//Encapsulate more cache?
	if pr.cache == nil {
		return nil, false
	}
	value, ok := pr.cache.data[key]
	return value, ok
}

//Cache caches a key, value on cache
func (pr Prompt) Cache(key string, value interface{}) error {
	if pr.cache == nil {
		return fmt.Errorf("Cache not initialized")
	}
	if pr.cache.data == nil {
		pr.cache.data = make(map[string]interface{})
	}
	pr.cache.data[key] = value
	return nil
}

//Compile processes the template and returns a prompt string
func (pr *Prompt) Compile(tmpl string) string {

	t, err := template.New("prompt").Funcs(pr.getFuncMap()).Parse(tmpl)
	if err != nil {
		log.Fatalf("unable to parse tmpl %s: %v", tmpl, err)
	}

	b := &bytes.Buffer{}
	err = t.Execute(b, struct{}{})
	if err != nil {
		log.Fatalf("unable to execute tmpl %s: %v", tmpl, err)
	}
	err = pr.cache.save()
	if err != nil {
		log.Printf("Unable to save cache: %v", err)
	}
	return b.String()
}

func (pr *Prompt) getFuncMap() template.FuncMap {
	return template.FuncMap{
		"load":   pr.Load,
		"wrap":   pr.Wrap,
		"suffix": pr.Suffix,
		"prefix": pr.Prefix,
	}
}

func (pr *Prompt) Load(plugin string) (string, error) {
	var p Plugin
	var ok bool
	var output string

	if p, ok = pr.plugins[plugin]; !ok {
		return "", fmt.Errorf("unable to find plugin: %s", plugin)
	}
	err := p.Load(pr)
	if err != nil {
		return "", fmt.Errorf("unable to load plugin %s: %v", plugin, err)
	}
	output, pr.tmpMode = p.Get(pr.format)

	if pr.debug {
		fmt.Fprintf(os.Stderr, "plugin %s output: %s\n", plugin, output)
	}
	return output, nil
}

func (pr *Prompt) Wrap(prefix, suffix string, input string) string {
	if input != "" {
		return pr.format(fmt.Sprintf("%s%s%s", prefix, input, suffix), pr.tmpMode...)
	}
	return ""
}
func (pr *Prompt) Prefix(prefix, input string) string {
	return pr.Wrap(prefix, "", input)
}
func (pr *Prompt) Suffix(suffix, input string) string {
	return pr.Wrap("", suffix, input)
}

//GetDefaultTemplates returns the default templates defined by the prompt package
func GetDefaultTemplates() []string {
	templates := make([]string, 0)
	for name := range defaultTemplates {
		templates = append(templates, name)
	}
	return templates
}

//GetTemplateOptions returns the default options for a default template
func GetTemplateOptions(template string) (map[string]interface{}, bool) {
	o, ok := defaultTemplatesOptions[template]
	return o, ok
}

//GetTemplate returns the a default template by its name
func GetTemplate(template string) (string, bool) {
	t, ok := defaultTemplates[template]
	return t, ok
}

//ShowHelpPlugin writes on w the plugin help
func ShowHelpPlugin(w io.Writer) {
	fmt.Fprintf(w, "Plugin help\n")
	fmt.Fprintf(w, "===============\n")
	for _, p := range availablePlugins {
		name := p.Name()
		desc, opt := p.Help()
		fmt.Fprintf(w, "Plugin: %s\n", name)
		fmt.Fprintf(w, "Description: %s\n", desc)
		if len(opt) > 0 {
			fmt.Fprintf(w, "Options:\n")
			for o, od := range opt {
				fmt.Fprintf(w, "  %s: %s\n", o, od)
			}
		}
		fmt.Fprintf(w, "\n")
	}
}

//ShowHelpTemplate writes on w the templating help
func ShowHelpTemplate(w io.Writer) {
	fmt.Fprintf(w, "Templating help\n")
	fmt.Fprintf(w, "===============\n")
	fmt.Fprintln(w,
		`This project uses gotemplate. There are 4 functions over what gotemplate can do:
		load "plugin": will load plugin
		prefix, suffix, wrap: will add text/symbols before, after or both to any plugin output if it has content`)
}

//Predefined templates and its options
var defaultTemplates map[string]string
var defaultTemplatesOptions map[string]map[string]interface{}

var availablePlugins []Plugin

func init() {
	availablePlugins = []Plugin{
		&plugin.Aws{},
		&plugin.Git{},
		&plugin.LastCommand{},
		&plugin.Path{},
		&plugin.Python{},
		&plugin.User{},
		&plugin.Hostname{},
		&plugin.UserChar{},
		&plugin.Golang{},
		&plugin.Kubernetes{},
		&plugin.ExitUserChar{},
	}

	defaultTemplates = map[string]string{
		"Evermeet": `{{load "python" |suffix " "}}{{load "aws"|suffix "|"}} {{load "user"|suffix "@"}}{{load "hostname"}} {{load "lastcommand"|suffix " "}}{{load "path"}}{{load "git"|prefix " "}}{{load "userchar"}}`,
		"Fedora":   `[ {{load "python"|wrap "(" ") "}}{{load "aws"|suffix "|"}}{{load "user"|suffix "@"}}{{load "hostname"}} {{load "lastcommand"|suffix " "}}{{load "path"}}{{load "git"|prefix " "}} ]{{load "userchar"}} `,
		"Prefered": `{{load "k8s"}}{{load "python"|wrap "("  ") "}}{{load "aws"|suffix "|"}}{{load "path"}}{{load "git"|prefix " "}}{{load "exituserchar"}} `,
	}
	defaultTemplatesOptions = map[string]map[string]interface{}{
		"Evermeet": map[string]interface{}{
			"path.fullpath": float64(1),
		},
		"Fedora": map[string]interface{}{
			"path.fullpath": float64(0),
		},
		"Prefered": map[string]interface{}{
			"path.fullpath": float64(3),
		},
	}
}

func detectShell() string {
	pid := os.Getppid()
	cmdlineFile := fmt.Sprintf("/proc/%d/cmdline", pid)
	cmdline, err := ioutil.ReadFile(cmdlineFile)
	if err != nil {
		cmdline = []byte(os.Getenv("SHELL"))
		if len(cmdline) <= 2 {
			return "unknown"
		}
	}

	shells := []string{"bash", "zsh", "fish"}
	for _, shell := range shells {
		if matches, _ := regexp.Match(shell, cmdline); matches {
			return shell
		}
	}
	return "unknown"
}
<commit_msg>clean init<commit_after>package prompt

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"text/template"

	"github.com/josledp/goprompt/prompt/plugin"
	"github.com/josledp/termcolor"
)

var availablePlugins = []Plugin{
	&plugin.Aws{},
	&plugin.Git{},
	&plugin.LastCommand{},
	&plugin.Path{},
	&plugin.Python{},
	&plugin.User{},
	&plugin.Hostname{},
	&plugin.UserChar{},
	&plugin.Golang{},
	&plugin.Kubernetes{},
	&plugin.ExitUserChar{},
}

var defaultTemplates = map[string]string{
	"Evermeet": `{{load "python" |suffix " "}}{{load "aws"|suffix "|"}} {{load "user"|suffix "@"}}{{load "hostname"}} {{load "lastcommand"|suffix " "}}{{load "path"}}{{load "git"|prefix " "}}{{load "userchar"}}`,
	"Fedora":   `[ {{load "python"|wrap "(" ") "}}{{load "aws"|suffix "|"}}{{load "user"|suffix "@"}}{{load "hostname"}} {{load "lastcommand"|suffix " "}}{{load "path"}}{{load "git"|prefix " "}} ]{{load "userchar"}} `,
	"Prefered": `{{load "k8s"}}{{load "python"|wrap "("  ") "}}{{load "aws"|suffix "|"}}{{load "path"}}{{load "git"|prefix " "}}{{load "exituserchar"}} `,
}

var defaultTemplatesOptions = map[string]map[string]interface{}{
	"Evermeet": map[string]interface{}{
		"path.fullpath": float64(1),
	},
	"Fedora": map[string]interface{}{
		"path.fullpath": float64(0),
	},
	"Prefered": map[string]interface{}{
		"path.fullpath": float64(3),
	},
}

//Prompt is the struct with the prompt options/config
type Prompt struct {
	options map[string]interface{}
	cache   *Cache
	plugins map[string]Plugin
	format  func(string, ...termcolor.Mode) string

	debug   bool
	tmpMode []termcolor.Mode
}

//Plugin is the interface all the plugins MUST implement
type Plugin interface {
	Name() string
	Help() (description string, options map[string]string)
	Load(pr plugin.Prompter) error
	Get(format func(string, ...termcolor.Mode) string) (string, []termcolor.Mode)
}

//New returns a new promp
func New(options map[string]interface{}, color, debug bool) Prompt {
	c, err := newCache()
	if err != nil {
		log.Printf("unable to initializa cache: %v", err)
	}
	// map plugin by name
	mPlugins := make(map[string]Plugin)
	for _, p := range availablePlugins {
		mPlugins[p.Name()] = p
	}
	var format func(string, ...termcolor.Mode) string

	if color {
		shell := detectShell()
		switch shell {
		case "bash":
			format = termcolor.EscapedFormat
		case "fish":
			format = termcolor.Format
		case "zsh":
			format = termcolor.Format

		default:
			//Defaut failsafe
			format = func(s string, modes ...termcolor.Mode) string { return s }
		}
	} else {
		format = func(s string, modes ...termcolor.Mode) string { return s }
	}

	return Prompt{
		options: options,
		cache:   c,
		plugins: mPlugins,
		format:  format,
		debug:   debug,
		tmpMode: nil,
	}
}

//GetOption returns the option value for key
func (pr Prompt) GetOption(key string) (interface{}, bool) {
	value, ok := pr.options[key]
	return value, ok
}

//GetCache recovers a value from cache
func (pr Prompt) GetCache(key string) (interface{}, bool) {
	//Encapsulate more cache?
	if pr.cache == nil {
		return nil, false
	}
	value, ok := pr.cache.data[key]
	return value, ok
}

//Cache caches a key, value on cache
func (pr Prompt) Cache(key string, value interface{}) error {
	if pr.cache == nil {
		return fmt.Errorf("Cache not initialized")
	}
	if pr.cache.data == nil {
		pr.cache.data = make(map[string]interface{})
	}
	pr.cache.data[key] = value
	return nil
}

//Compile processes the template and returns a prompt string
func (pr *Prompt) Compile(tmpl string) string {

	t, err := template.New("prompt").Funcs(pr.getFuncMap()).Parse(tmpl)
	if err != nil {
		log.Fatalf("unable to parse tmpl %s: %v", tmpl, err)
	}

	b := &bytes.Buffer{}
	err = t.Execute(b, struct{}{})
	if err != nil {
		log.Fatalf("unable to execute tmpl %s: %v", tmpl, err)
	}
	err = pr.cache.save()
	if err != nil {
		log.Printf("Unable to save cache: %v", err)
	}
	return b.String()
}

func (pr *Prompt) getFuncMap() template.FuncMap {
	return template.FuncMap{
		"load":   pr.Load,
		"wrap":   pr.Wrap,
		"suffix": pr.Suffix,
		"prefix": pr.Prefix,
	}
}

func (pr *Prompt) Load(plugin string) (string, error) {
	var p Plugin
	var ok bool
	var output string

	if p, ok = pr.plugins[plugin]; !ok {
		return "", fmt.Errorf("unable to find plugin: %s", plugin)
	}
	err := p.Load(pr)
	if err != nil {
		return "", fmt.Errorf("unable to load plugin %s: %v", plugin, err)
	}
	output, pr.tmpMode = p.Get(pr.format)

	if pr.debug {
		fmt.Fprintf(os.Stderr, "plugin %s output: %s\n", plugin, output)
	}
	return output, nil
}

func (pr *Prompt) Wrap(prefix, suffix string, input string) string {
	if input == "" {
		return ""
	}
	if prefix != "" {
		prefix = pr.format(prefix, pr.tmpMode...)
	}
	if suffix != "" {
		suffix = pr.format(suffix, pr.tmpMode...)
	}
	return fmt.Sprintf("%s%s%s", prefix, input, suffix)
}
func (pr *Prompt) Prefix(prefix, input string) string {
	return pr.Wrap(prefix, "", input)
}
func (pr *Prompt) Suffix(suffix, input string) string {
	return pr.Wrap("", suffix, input)
}

//GetDefaultTemplates returns the default templates defined by the prompt package
func GetDefaultTemplates() []string {
	templates := make([]string, 0)
	for name := range defaultTemplates {
		templates = append(templates, name)
	}
	return templates
}

//GetTemplateOptions returns the default options for a default template
func GetTemplateOptions(template string) (map[string]interface{}, bool) {
	o, ok := defaultTemplatesOptions[template]
	return o, ok
}

//GetTemplate returns the a default template by its name
func GetTemplate(template string) (string, bool) {
	t, ok := defaultTemplates[template]
	return t, ok
}

//ShowHelpPlugin writes on w the plugin help
func ShowHelpPlugin(w io.Writer) {
	fmt.Fprintf(w, "Plugin help\n")
	fmt.Fprintf(w, "===============\n")
	for _, p := range availablePlugins {
		name := p.Name()
		desc, opt := p.Help()
		fmt.Fprintf(w, "Plugin: %s\n", name)
		fmt.Fprintf(w, "Description: %s\n", desc)
		if len(opt) > 0 {
			fmt.Fprintf(w, "Options:\n")
			for o, od := range opt {
				fmt.Fprintf(w, "  %s: %s\n", o, od)
			}
		}
		fmt.Fprintf(w, "\n")
	}
}

//ShowHelpTemplate writes on w the templating help
func ShowHelpTemplate(w io.Writer) {
	fmt.Fprintf(w, "Templating help\n")
	fmt.Fprintf(w, "===============\n")
	fmt.Fprintln(w,
		`This project uses gotemplate. There are 4 functions over what gotemplate can do:
		load "plugin": will load plugin
		prefix, suffix, wrap: will add text/symbols before, after or both to any plugin output if it has content`)
}

func detectShell() string {
	pid := os.Getppid()
	cmdlineFile := fmt.Sprintf("/proc/%d/cmdline", pid)
	cmdline, err := ioutil.ReadFile(cmdlineFile)
	if err != nil {
		cmdline = []byte(os.Getenv("SHELL"))
		if len(cmdline) <= 2 {
			return "unknown"
		}
	}

	shells := []string{"bash", "zsh", "fish"}
	for _, shell := range shells {
		if matches, _ := regexp.Match(shell, cmdline); matches {
			return shell
		}
	}
	return "unknown"
}
<|endoftext|>


<commit_before>package deter

import (
	"github.com/cycps/addie"
	"github.com/deter-project/go-spi/spi"
	"log"
	"reflect"
)

func compComp(c *addie.Computer) spi.Computer {

	var _c spi.Computer
	_c.Name = c.Name
	_c.OSs = []spi.OS{spi.OS{c.OS, ""}}

	for _, i := range c.Interfaces {
		_c.Interfaces = append(_c.Interfaces,
			spi.Interface{
				Name:      i.Name,
				Substrate: "TODO", //this gets resolved when the links get added
				Capacity:  spi.Capacity{float64(i.Capacity), spi.Kind{"max"}},
				Latency:   spi.Latency{float64(i.Latency), spi.Kind{"max"}},
			},
		)
	}

	return _c

}

func rtrComp(r *addie.Router) spi.Computer {

	var c spi.Computer
	c.Name = r.Name
	c.OSs = []spi.OS{spi.OS{"Ubuntu Click", "Router"}}

	for _, i := range r.Interfaces {
		c.Interfaces = append(c.Interfaces,
			spi.Interface{
				Name:      i.Name,
				Substrate: "TODO", //this gets resolved when the links get added
				Capacity:  spi.Capacity{float64(i.Capacity), spi.Kind{"max"}},
				Latency:   spi.Latency{float64(i.Latency), spi.Kind{"max"}},
			},
		)
	}

	return c

}

func swSubstrate(sw *addie.Switch) spi.Substrate {

	var ss spi.Substrate
	ss.Name = sw.Name
	ss.Capacity = spi.Capacity{float64(sw.Capacity), spi.Kind{"max"}}
	ss.Latency = spi.Latency{float64(sw.Latency), spi.Kind{"max"}}

	return ss

}

func updateIfxSubstrate(ifxName, ssName string, c *spi.Computer) {

	for i, _ := range c.Interfaces {
		if c.Interfaces[i].Name == ifxName {
			c.Interfaces[i].Substrate = ssName
			break
		}
	}

}

func updateEndpoint(ssName string, ifr addie.NetIfRef, dsg *addie.Design,
	xp *spi.Experiment,
	cMap map[addie.Id]*spi.Computer) {

	e, ok := dsg.Elements[ifr.Id]

	if !ok {
		log.Printf("link '%s' references element '%v' but no such element exists",
			ssName, ifr.Id)
		return
	}

	switch e.(type) {
	case addie.Computer:
		c := e.(addie.Computer)
		updateIfxSubstrate(ifr.IfName, ssName, cMap[c.Id])

	case addie.Router:
		r := e.(addie.Router)
		updateIfxSubstrate(ifr.IfName, ssName, cMap[r.Id])

	default:
		log.Printf("p2p link '%s' references illegal element '%v'", ssName, ifr.Id)
	}

}

func linkSubstrate(link *addie.Link, dsg *addie.Design,
	xp *spi.Experiment,
	cMap map[addie.Id]*spi.Computer,
	sMap map[addie.Id]*spi.Substrate) spi.Substrate {

	var ss spi.Substrate
	ss.Name = link.Name
	ss.Capacity = spi.Capacity{float64(link.Capacity), spi.Kind{"max"}}
	ss.Latency = spi.Latency{float64(link.Latency), spi.Kind{"max"}}

	a, ok := dsg.Elements[link.Endpoints[0].Id]
	if !ok {
		log.Printf("link '%s' references element '%v' but no such element exists",
			link.Name, link.Endpoints[0].Id)
		return ss
	}
	b, ok := dsg.Elements[link.Endpoints[1].Id]
	if !ok {
		log.Printf("link '%s' references element '%v' but no such element exists",
			link.Name, link.Endpoints[0].Id)
		return ss
	}

	ta := reflect.TypeOf(a).Name()
	tb := reflect.TypeOf(b).Name()

	taIsHost := ta == "Computer" || ta == "Router"
	tbIsHost := tb == "Computer" || tb == "Router"

	if taIsHost && tbIsHost {
		updateEndpoint(link.Name, link.Endpoints[0], dsg, xp, cMap)
		updateEndpoint(link.Name, link.Endpoints[1], dsg, xp, cMap)
	} else if taIsHost && !tbIsHost {
		sw := b.(addie.Switch)
		updateEndpoint(sw.Name, link.Endpoints[0], dsg, xp, cMap)
	} else if !taIsHost && tbIsHost {
		sw := a.(addie.Switch)
		updateEndpoint(sw.Name, link.Endpoints[1], dsg, xp, cMap)
	}

	return ss
}

func designTopDL(dsg *addie.Design) spi.Experiment {

	var xp spi.Experiment

	cMap := make(map[addie.Id]*spi.Computer)
	sMap := make(map[addie.Id]*spi.Substrate)

	var links []*addie.Link

	for _, e := range dsg.Elements {

		switch e.(type) {
		case addie.Computer:
			c := e.(addie.Computer)
			_c := compComp(&c)
			cMap[c.Id] = &_c
			xp.Elements.Elements = append(xp.Elements.Elements, _c)

		case addie.Switch:
			sw := e.(addie.Switch)
			ss := swSubstrate(&sw)
			sMap[sw.Id] = &ss
			xp.Substrates = append(xp.Substrates, ss)

		case addie.Router:
			rtr := e.(addie.Router)
			c := rtrComp(&rtr)
			cMap[rtr.Id] = &c
			xp.Elements.Elements = append(xp.Elements.Elements, c)

		case addie.Link:
			lnk := e.(addie.Link)
			links = append(links, &lnk)
		}

	}

	for _, l := range links {
		xp.Substrates = append(xp.Substrates, linkSubstrate(l, dsg, &xp, cMap, sMap))
	}

	return xp
}
<commit_msg>spi topdl visualizer produces same picture as cypress :)<commit_after>package deter

import (
	"github.com/cycps/addie"
	"github.com/deter-project/go-spi/spi"
	"log"
	"reflect"
)

func compComp(c *addie.Computer) spi.Computer {

	var _c spi.Computer
	_c.Name = c.Name
	_c.OSs = []spi.OS{spi.OS{c.OS, ""}}

	for _, i := range c.Interfaces {
		_c.Interfaces = append(_c.Interfaces,
			spi.Interface{
				Name:      i.Name,
				Substrate: "TODO", //this gets resolved when the links get added
				Capacity:  spi.Capacity{float64(i.Capacity), spi.Kind{"max"}},
				Latency:   spi.Latency{float64(i.Latency), spi.Kind{"max"}},
			},
		)
	}

	return _c

}

func rtrComp(r *addie.Router) spi.Computer {

	var c spi.Computer
	c.Name = r.Name
	c.OSs = []spi.OS{spi.OS{"Ubuntu Click", "Router"}}

	for _, i := range r.Interfaces {
		c.Interfaces = append(c.Interfaces,
			spi.Interface{
				Name:      i.Name,
				Substrate: "TODO", //this gets resolved when the links get added
				Capacity:  spi.Capacity{float64(i.Capacity), spi.Kind{"max"}},
				Latency:   spi.Latency{float64(i.Latency), spi.Kind{"max"}},
			},
		)
	}

	return c

}

func swSubstrate(sw *addie.Switch) spi.Substrate {

	var ss spi.Substrate
	ss.Name = sw.Name
	ss.Capacity = spi.Capacity{float64(sw.Capacity), spi.Kind{"max"}}
	ss.Latency = spi.Latency{float64(sw.Latency), spi.Kind{"max"}}

	return ss

}

func updateIfxSubstrate(ifxName, ssName string, c *spi.Computer) {

	for i, _ := range c.Interfaces {
		if c.Interfaces[i].Name == ifxName {
			c.Interfaces[i].Substrate = ssName
			break
		}
	}

}

func updateEndpoint(ssName string, ifr addie.NetIfRef, dsg *addie.Design,
	xp *spi.Experiment,
	cMap map[addie.Id]*spi.Computer) {

	e, ok := dsg.Elements[ifr.Id]

	if !ok {
		log.Printf("link '%s' references element '%v' but no such element exists",
			ssName, ifr.Id)
		return
	}

	switch e.(type) {
	case addie.Computer:
		c := e.(addie.Computer)
		updateIfxSubstrate(ifr.IfName, ssName, cMap[c.Id])

	case addie.Router:
		r := e.(addie.Router)
		updateIfxSubstrate(ifr.IfName, ssName, cMap[r.Id])

	default:
		log.Printf("p2p link '%s' references illegal element '%v'", ssName, ifr.Id)
	}

}

func linkSubstrate(link *addie.Link, dsg *addie.Design,
	xp *spi.Experiment,
	cMap map[addie.Id]*spi.Computer,
	sMap map[addie.Id]*spi.Substrate) *spi.Substrate {

	var ss spi.Substrate
	ss.Name = link.Name
	ss.Capacity = spi.Capacity{float64(link.Capacity), spi.Kind{"max"}}
	ss.Latency = spi.Latency{float64(link.Latency), spi.Kind{"max"}}

	a, ok := dsg.Elements[link.Endpoints[0].Id]
	if !ok {
		log.Printf("link '%s' references element '%v' but no such element exists",
			link.Name, link.Endpoints[0].Id)
		return nil
	}
	b, ok := dsg.Elements[link.Endpoints[1].Id]
	if !ok {
		log.Printf("link '%s' references element '%v' but no such element exists",
			link.Name, link.Endpoints[0].Id)
		return nil
	}

	ta := reflect.TypeOf(a).Name()
	tb := reflect.TypeOf(b).Name()

	taIsHost := ta == "Computer" || ta == "Router"
	tbIsHost := tb == "Computer" || tb == "Router"

	if taIsHost && tbIsHost {
		updateEndpoint(link.Name, link.Endpoints[0], dsg, xp, cMap)
		updateEndpoint(link.Name, link.Endpoints[1], dsg, xp, cMap)
		return &ss
	} else if taIsHost && !tbIsHost {
		sw := b.(addie.Switch)
		updateEndpoint(sw.Name, link.Endpoints[0], dsg, xp, cMap)
		return nil
	} else if !taIsHost && tbIsHost {
		sw := a.(addie.Switch)
		updateEndpoint(sw.Name, link.Endpoints[1], dsg, xp, cMap)
		return nil
	}

	return nil
}

func designTopDL(dsg *addie.Design) spi.Experiment {

	var xp spi.Experiment

	cMap := make(map[addie.Id]*spi.Computer)
	sMap := make(map[addie.Id]*spi.Substrate)

	var links []*addie.Link

	for _, e := range dsg.Elements {

		switch e.(type) {
		case addie.Computer:
			c := e.(addie.Computer)
			_c := compComp(&c)
			cMap[c.Id] = &_c
			xp.Elements.Elements = append(xp.Elements.Elements, _c)

		case addie.Switch:
			sw := e.(addie.Switch)
			ss := swSubstrate(&sw)
			sMap[sw.Id] = &ss
			xp.Substrates = append(xp.Substrates, ss)

		case addie.Router:
			rtr := e.(addie.Router)
			c := rtrComp(&rtr)
			cMap[rtr.Id] = &c
			xp.Elements.Elements = append(xp.Elements.Elements, c)

		case addie.Link:
			lnk := e.(addie.Link)
			links = append(links, &lnk)
		}

	}

	for _, l := range links {
		_l := linkSubstrate(l, dsg, &xp, cMap, sMap)
		if _l != nil {
			xp.Substrates = append(xp.Substrates, *_l)
		}
	}

	return xp
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

// Package certificates implements an abstract controller that is useful for
// building controllers that manage CSRs
package certificates

import (
	"fmt"
	"time"

	"golang.org/x/time/rate"

	certificates "k8s.io/api/certificates/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	certificatesinformers "k8s.io/client-go/informers/certificates/v1"
	clientset "k8s.io/client-go/kubernetes"
	v1core "k8s.io/client-go/kubernetes/typed/core/v1"
	certificateslisters "k8s.io/client-go/listers/certificates/v1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"
	"k8s.io/client-go/util/workqueue"
	"k8s.io/klog/v2"
	"k8s.io/kubernetes/pkg/controller"
)

type CertificateController struct {
	// name is an identifier for this particular controller instance.
	name string

	kubeClient clientset.Interface

	csrLister  certificateslisters.CertificateSigningRequestLister
	csrsSynced cache.InformerSynced

	handler func(*certificates.CertificateSigningRequest) error

	queue workqueue.RateLimitingInterface
}

func NewCertificateController(
	name string,
	kubeClient clientset.Interface,
	csrInformer certificatesinformers.CertificateSigningRequestInformer,
	handler func(*certificates.CertificateSigningRequest) error,
) *CertificateController {
	// Send events to the apiserver
	eventBroadcaster := record.NewBroadcaster()
	eventBroadcaster.StartStructuredLogging(0)
	eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: kubeClient.CoreV1().Events("")})

	cc := &CertificateController{
		name:       name,
		kubeClient: kubeClient,
		queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewMaxOfRateLimiter(
			workqueue.NewItemExponentialFailureRateLimiter(200*time.Millisecond, 1000*time.Second),
			// 10 qps, 100 bucket size.  This is only for retry speed and its only the overall factor (not per item)
			&workqueue.BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
		), "certificate"),
		handler: handler,
	}

	// Manage the addition/update of certificate requests
	csrInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			csr := obj.(*certificates.CertificateSigningRequest)
			klog.V(4).Infof("Adding certificate request %s", csr.Name)
			cc.enqueueCertificateRequest(obj)
		},
		UpdateFunc: func(old, new interface{}) {
			oldCSR := old.(*certificates.CertificateSigningRequest)
			klog.V(4).Infof("Updating certificate request %s", oldCSR.Name)
			cc.enqueueCertificateRequest(new)
		},
		DeleteFunc: func(obj interface{}) {
			csr, ok := obj.(*certificates.CertificateSigningRequest)
			if !ok {
				tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
				if !ok {
					klog.V(2).Infof("Couldn't get object from tombstone %#v", obj)
					return
				}
				csr, ok = tombstone.Obj.(*certificates.CertificateSigningRequest)
				if !ok {
					klog.V(2).Infof("Tombstone contained object that is not a CSR: %#v", obj)
					return
				}
			}
			klog.V(4).Infof("Deleting certificate request %s", csr.Name)
			cc.enqueueCertificateRequest(obj)
		},
	})
	cc.csrLister = csrInformer.Lister()
	cc.csrsSynced = csrInformer.Informer().HasSynced
	return cc
}

// Run the main goroutine responsible for watching and syncing jobs.
func (cc *CertificateController) Run(workers int, stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()
	defer cc.queue.ShutDown()

	klog.Infof("Starting certificate controller %q", cc.name)
	defer klog.Infof("Shutting down certificate controller %q", cc.name)

	if !cache.WaitForNamedCacheSync(fmt.Sprintf("certificate-%s", cc.name), stopCh, cc.csrsSynced) {
		return
	}

	for i := 0; i < workers; i++ {
		go wait.Until(cc.worker, time.Second, stopCh)
	}

	<-stopCh
}

// worker runs a thread that dequeues CSRs, handles them, and marks them done.
func (cc *CertificateController) worker() {
	for cc.processNextWorkItem() {
	}
}

// processNextWorkItem deals with one key off the queue.  It returns false when it's time to quit.
func (cc *CertificateController) processNextWorkItem() bool {
	cKey, quit := cc.queue.Get()
	if quit {
		return false
	}
	defer cc.queue.Done(cKey)

	if err := cc.syncFunc(cKey.(string)); err != nil {
		cc.queue.AddRateLimited(cKey)
		if _, ignorable := err.(ignorableError); !ignorable {
			utilruntime.HandleError(fmt.Errorf("Sync %v failed with : %v", cKey, err))
		} else {
			klog.V(4).Infof("Sync %v failed with : %v", cKey, err)
		}
		return true
	}

	cc.queue.Forget(cKey)
	return true

}

func (cc *CertificateController) enqueueCertificateRequest(obj interface{}) {
	key, err := controller.KeyFunc(obj)
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("Couldn't get key for object %+v: %v", obj, err))
		return
	}
	cc.queue.Add(key)
}

// maybeSignCertificate will inspect the certificate request and, if it has
// been approved and meets policy expectations, generate an X509 cert using the
// cluster CA assets. If successful it will update the CSR approve subresource
// with the signed certificate.
func (cc *CertificateController) syncFunc(key string) error {
	startTime := time.Now()
	defer func() {
		klog.V(4).Infof("Finished syncing certificate request %q (%v)", key, time.Since(startTime))
	}()
	csr, err := cc.csrLister.Get(key)
	if errors.IsNotFound(err) {
		klog.V(3).Infof("csr has been deleted: %v", key)
		return nil
	}
	if err != nil {
		return err
	}

	if len(csr.Status.Certificate) > 0 {
		// no need to do anything because it already has a cert
		return nil
	}

	// need to operate on a copy so we don't mutate the csr in the shared cache
	csr = csr.DeepCopy()
	return cc.handler(csr)
}

// IgnorableError returns an error that we shouldn't handle (i.e. log) because
// it's spammy and usually user error. Instead we will log these errors at a
// higher log level. We still need to throw these errors to signal that the
// sync should be retried.
func IgnorableError(s string, args ...interface{}) ignorableError {
	return ignorableError(fmt.Sprintf(s, args...))
}

type ignorableError string

func (e ignorableError) Error() string {
	return string(e)
}
<commit_msg>[pkg/controller/certificates]: remove staled func comments<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

// Package certificates implements an abstract controller that is useful for
// building controllers that manage CSRs
package certificates

import (
	"fmt"
	"time"

	"golang.org/x/time/rate"

	certificates "k8s.io/api/certificates/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	certificatesinformers "k8s.io/client-go/informers/certificates/v1"
	clientset "k8s.io/client-go/kubernetes"
	v1core "k8s.io/client-go/kubernetes/typed/core/v1"
	certificateslisters "k8s.io/client-go/listers/certificates/v1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"
	"k8s.io/client-go/util/workqueue"
	"k8s.io/klog/v2"
	"k8s.io/kubernetes/pkg/controller"
)

type CertificateController struct {
	// name is an identifier for this particular controller instance.
	name string

	kubeClient clientset.Interface

	csrLister  certificateslisters.CertificateSigningRequestLister
	csrsSynced cache.InformerSynced

	handler func(*certificates.CertificateSigningRequest) error

	queue workqueue.RateLimitingInterface
}

func NewCertificateController(
	name string,
	kubeClient clientset.Interface,
	csrInformer certificatesinformers.CertificateSigningRequestInformer,
	handler func(*certificates.CertificateSigningRequest) error,
) *CertificateController {
	// Send events to the apiserver
	eventBroadcaster := record.NewBroadcaster()
	eventBroadcaster.StartStructuredLogging(0)
	eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: kubeClient.CoreV1().Events("")})

	cc := &CertificateController{
		name:       name,
		kubeClient: kubeClient,
		queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewMaxOfRateLimiter(
			workqueue.NewItemExponentialFailureRateLimiter(200*time.Millisecond, 1000*time.Second),
			// 10 qps, 100 bucket size.  This is only for retry speed and its only the overall factor (not per item)
			&workqueue.BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
		), "certificate"),
		handler: handler,
	}

	// Manage the addition/update of certificate requests
	csrInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			csr := obj.(*certificates.CertificateSigningRequest)
			klog.V(4).Infof("Adding certificate request %s", csr.Name)
			cc.enqueueCertificateRequest(obj)
		},
		UpdateFunc: func(old, new interface{}) {
			oldCSR := old.(*certificates.CertificateSigningRequest)
			klog.V(4).Infof("Updating certificate request %s", oldCSR.Name)
			cc.enqueueCertificateRequest(new)
		},
		DeleteFunc: func(obj interface{}) {
			csr, ok := obj.(*certificates.CertificateSigningRequest)
			if !ok {
				tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
				if !ok {
					klog.V(2).Infof("Couldn't get object from tombstone %#v", obj)
					return
				}
				csr, ok = tombstone.Obj.(*certificates.CertificateSigningRequest)
				if !ok {
					klog.V(2).Infof("Tombstone contained object that is not a CSR: %#v", obj)
					return
				}
			}
			klog.V(4).Infof("Deleting certificate request %s", csr.Name)
			cc.enqueueCertificateRequest(obj)
		},
	})
	cc.csrLister = csrInformer.Lister()
	cc.csrsSynced = csrInformer.Informer().HasSynced
	return cc
}

// Run the main goroutine responsible for watching and syncing jobs.
func (cc *CertificateController) Run(workers int, stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()
	defer cc.queue.ShutDown()

	klog.Infof("Starting certificate controller %q", cc.name)
	defer klog.Infof("Shutting down certificate controller %q", cc.name)

	if !cache.WaitForNamedCacheSync(fmt.Sprintf("certificate-%s", cc.name), stopCh, cc.csrsSynced) {
		return
	}

	for i := 0; i < workers; i++ {
		go wait.Until(cc.worker, time.Second, stopCh)
	}

	<-stopCh
}

// worker runs a thread that dequeues CSRs, handles them, and marks them done.
func (cc *CertificateController) worker() {
	for cc.processNextWorkItem() {
	}
}

// processNextWorkItem deals with one key off the queue.  It returns false when it's time to quit.
func (cc *CertificateController) processNextWorkItem() bool {
	cKey, quit := cc.queue.Get()
	if quit {
		return false
	}
	defer cc.queue.Done(cKey)

	if err := cc.syncFunc(cKey.(string)); err != nil {
		cc.queue.AddRateLimited(cKey)
		if _, ignorable := err.(ignorableError); !ignorable {
			utilruntime.HandleError(fmt.Errorf("Sync %v failed with : %v", cKey, err))
		} else {
			klog.V(4).Infof("Sync %v failed with : %v", cKey, err)
		}
		return true
	}

	cc.queue.Forget(cKey)
	return true

}

func (cc *CertificateController) enqueueCertificateRequest(obj interface{}) {
	key, err := controller.KeyFunc(obj)
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("Couldn't get key for object %+v: %v", obj, err))
		return
	}
	cc.queue.Add(key)
}

func (cc *CertificateController) syncFunc(key string) error {
	startTime := time.Now()
	defer func() {
		klog.V(4).Infof("Finished syncing certificate request %q (%v)", key, time.Since(startTime))
	}()
	csr, err := cc.csrLister.Get(key)
	if errors.IsNotFound(err) {
		klog.V(3).Infof("csr has been deleted: %v", key)
		return nil
	}
	if err != nil {
		return err
	}

	if len(csr.Status.Certificate) > 0 {
		// no need to do anything because it already has a cert
		return nil
	}

	// need to operate on a copy so we don't mutate the csr in the shared cache
	csr = csr.DeepCopy()
	return cc.handler(csr)
}

// IgnorableError returns an error that we shouldn't handle (i.e. log) because
// it's spammy and usually user error. Instead we will log these errors at a
// higher log level. We still need to throw these errors to signal that the
// sync should be retried.
func IgnorableError(s string, args ...interface{}) ignorableError {
	return ignorableError(fmt.Sprintf(s, args...))
}

type ignorableError string

func (e ignorableError) Error() string {
	return string(e)
}
<|endoftext|>


<commit_before>package management

import (
	"fmt"

	v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
	"github.com/rancher/rancher/pkg/types/config"
	v1 "k8s.io/api/core/v1"
	"k8s.io/api/policy/v1beta1"
	"k8s.io/apimachinery/pkg/api/errors"
	v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const runAsAny = "RunAsAny"
const mustRunAs = "MustRunAs"

func addDefaultPodSecurityPolicyTemplates(management *config.ManagementContext) error {
	pspts := management.Management.PodSecurityPolicyTemplates("")
	policies := []*v3.PodSecurityPolicyTemplate{
		{
			ObjectMeta: v12.ObjectMeta{
				Name: "unrestricted",
			},
			Spec: v1beta1.PodSecurityPolicySpec{
				Privileged:               true,
				AllowPrivilegeEscalation: toBoolPtr(true),
				AllowedCapabilities: []v1.Capability{
					"*",
				},
				Volumes: []v1beta1.FSType{
					"*",
				},
				HostNetwork: true,
				HostPorts: []v1beta1.HostPortRange{
					{Min: 0, Max: 65535},
				},
				HostIPC: true,
				HostPID: true,
				RunAsUser: v1beta1.RunAsUserStrategyOptions{
					Rule: runAsAny,
				},
				SELinux: v1beta1.SELinuxStrategyOptions{
					Rule: runAsAny,
				},
				SupplementalGroups: v1beta1.SupplementalGroupsStrategyOptions{
					Rule: runAsAny,
				},
				FSGroup: v1beta1.FSGroupStrategyOptions{
					Rule: runAsAny,
				},
			},
			Description: "This is the default unrestricted Pod Security Policy Template.  It is the most permissive " +
				"Pod Security Policy that can be created in Kubernetes and is equivalent to running Kubernetes " +
				"without Pod Security Policies enabled.",
		},
		{
			ObjectMeta: v12.ObjectMeta{
				Name: "restricted",
			},
			Spec: v1beta1.PodSecurityPolicySpec{
				Privileged:               false,
				AllowPrivilegeEscalation: toBoolPtr(false),
				RequiredDropCapabilities: []v1.Capability{
					"ALL",
				},
				Volumes: []v1beta1.FSType{
					"configMap",
					"emptyDir",
					"projected",
					"secret",
					"downwardAPI",
					"persistentVolumeClaim",
				},
				HostNetwork: false,
				HostIPC:     false,
				HostPID:     false,
				RunAsUser: v1beta1.RunAsUserStrategyOptions{
					Rule: runAsAny,
				},
				SELinux: v1beta1.SELinuxStrategyOptions{
					Rule: runAsAny,
				},
				SupplementalGroups: v1beta1.SupplementalGroupsStrategyOptions{
					Rule: mustRunAs,
					Ranges: []v1beta1.IDRange{
						{Min: 1, Max: 65535},
					},
				},
				FSGroup: v1beta1.FSGroupStrategyOptions{
					Rule: mustRunAs,
					Ranges: []v1beta1.IDRange{
						{Min: 1, Max: 65535},
					},
				},
				ReadOnlyRootFilesystem: false,
			},
			Description: "This is the default restricted Pod Security Policy Template.  It restricts many user " +
				"actions and does not allow privilege escalation.",
		},
	}
	for _, policy := range policies {
		_, err := pspts.Create(policy)
		if err != nil && !errors.IsAlreadyExists(err) {
			return fmt.Errorf("error creating default pspt: %v", err)
		}
	}

	return nil
}

func toBoolPtr(boolean bool) *bool {
	return &boolean
}
<commit_msg>Add restricted-noroot PSP policy to match upstream Kubernetes restricted PSP. (#36367)<commit_after>package management

import (
	"fmt"

	v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
	"github.com/rancher/rancher/pkg/types/config"
	v1 "k8s.io/api/core/v1"
	"k8s.io/api/policy/v1beta1"
	"k8s.io/apimachinery/pkg/api/errors"
	v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const runAsAny = "RunAsAny"
const mustRunAs = "MustRunAs"
const mustRunAsNonRoot = "MustRunAsNonRoot"

func addDefaultPodSecurityPolicyTemplates(management *config.ManagementContext) error {
	pspts := management.Management.PodSecurityPolicyTemplates("")
	policies := []*v3.PodSecurityPolicyTemplate{
		{
			ObjectMeta: v12.ObjectMeta{
				Name: "unrestricted",
			},
			Spec: v1beta1.PodSecurityPolicySpec{
				Privileged:               true,
				AllowPrivilegeEscalation: toBoolPtr(true),
				AllowedCapabilities: []v1.Capability{
					"*",
				},
				Volumes: []v1beta1.FSType{
					"*",
				},
				HostNetwork: true,
				HostPorts: []v1beta1.HostPortRange{
					{Min: 0, Max: 65535},
				},
				HostIPC: true,
				HostPID: true,
				RunAsUser: v1beta1.RunAsUserStrategyOptions{
					Rule: runAsAny,
				},
				SELinux: v1beta1.SELinuxStrategyOptions{
					Rule: runAsAny,
				},
				SupplementalGroups: v1beta1.SupplementalGroupsStrategyOptions{
					Rule: runAsAny,
				},
				FSGroup: v1beta1.FSGroupStrategyOptions{
					Rule: runAsAny,
				},
			},
			Description: "This is the default unrestricted Pod Security Policy Template. It is the most permissive " +
				"Pod Security Policy that can be created in Kubernetes and is equivalent to running Kubernetes " +
				"without Pod Security Policies enabled.",
		},
		{
			ObjectMeta: v12.ObjectMeta{
				Name: "restricted",
			},
			Spec: v1beta1.PodSecurityPolicySpec{
				Privileged:               false,
				AllowPrivilegeEscalation: toBoolPtr(false),
				RequiredDropCapabilities: []v1.Capability{
					"ALL",
				},
				Volumes: []v1beta1.FSType{
					"configMap",
					"emptyDir",
					"projected",
					"secret",
					"downwardAPI",
					"persistentVolumeClaim",
				},
				HostNetwork: false,
				HostIPC:     false,
				HostPID:     false,
				RunAsUser: v1beta1.RunAsUserStrategyOptions{
					Rule: runAsAny,
				},
				SELinux: v1beta1.SELinuxStrategyOptions{
					Rule: runAsAny,
				},
				SupplementalGroups: v1beta1.SupplementalGroupsStrategyOptions{
					Rule: mustRunAs,
					Ranges: []v1beta1.IDRange{
						{Min: 1, Max: 65535},
					},
				},
				FSGroup: v1beta1.FSGroupStrategyOptions{
					Rule: mustRunAs,
					Ranges: []v1beta1.IDRange{
						{Min: 1, Max: 65535},
					},
				},
				ReadOnlyRootFilesystem: false,
			},
			Description: "This is the default restricted Pod Security Policy Template. It restricts many user " +
				"actions and does not allow privilege escalation.",
		},
		{
			ObjectMeta: v12.ObjectMeta{
				Name: "restricted-noroot",
			},
			Spec: v1beta1.PodSecurityPolicySpec{
				Privileged:               false,
				AllowPrivilegeEscalation: toBoolPtr(false),
				RequiredDropCapabilities: []v1.Capability{
					"ALL",
				},
				Volumes: []v1beta1.FSType{
					"configMap",
					"emptyDir",
					"projected",
					"secret",
					"downwardAPI",
					"csi",
					"persistentVolumeClaim",
				},
				HostNetwork: false,
				HostIPC:     false,
				HostPID:     false,
				RunAsUser: v1beta1.RunAsUserStrategyOptions{
					Rule: mustRunAsNonRoot,
				},
				SELinux: v1beta1.SELinuxStrategyOptions{
					Rule: runAsAny,
				},
				SupplementalGroups: v1beta1.SupplementalGroupsStrategyOptions{
					Rule: mustRunAs,
					Ranges: []v1beta1.IDRange{
						{Min: 1, Max: 65535},
					},
				},
				FSGroup: v1beta1.FSGroupStrategyOptions{
					Rule: mustRunAs,
					Ranges: []v1beta1.IDRange{
						{Min: 1, Max: 65535},
					},
				},
				ReadOnlyRootFilesystem: false,
			},
			Description: "This is the restricted Pod Security Policy Template to match upstream Kubernetes restricted PSP. " +
				"It restricts all user actions, does not allow privilege escalation and requires containers to run without root privileges.",
		},
	}
	for _, policy := range policies {
		_, err := pspts.Create(policy)
		if err != nil && !errors.IsAlreadyExists(err) {
			return fmt.Errorf("error creating default pspt: %v", err)
		}
	}

	return nil
}

func toBoolPtr(boolean bool) *bool {
	return &boolean
}
<|endoftext|>


<commit_before>package globaldns

import (
	"context"
	"fmt"
	"net"
	"strings"

	"github.com/rancher/rancher/pkg/controllers/management/rbac"
	v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
	"github.com/rancher/rancher/pkg/namespace"
	"github.com/rancher/rancher/pkg/types/config"
	"github.com/sirupsen/logrus"

	"strconv"

	apiv1 "k8s.io/api/core/v1"
	"k8s.io/api/extensions/v1beta1"
	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/intstr"
	clientv1beta1 "k8s.io/client-go/kubernetes/typed/extensions/v1beta1"
)

const (
	GlobaldnsController    = "mgmt-global-dns-controller"
	annotationIngressClass = "kubernetes.io/ingress.class"
	annotationFilter       = "annotation-filter"
	annotationDNSTTL       = "external-dns.alpha.kubernetes.io/ttl"
	defaultIngressClass    = "rancher-external-dns"
)

type GDController struct {
	ingresses               clientv1beta1.IngressInterface //need to use client-go IngressInterface to update Ingress.Status field
	managementContext       *config.ManagementContext
	globalDNSProviderLister v3.GlobalDnsProviderLister
}

func newGlobalDNSController(ctx context.Context, mgmt *config.ManagementContext) *GDController {
	n := &GDController{
		ingresses:               mgmt.K8sClient.ExtensionsV1beta1().Ingresses(namespace.GlobalNamespace),
		managementContext:       mgmt,
		globalDNSProviderLister: mgmt.Management.GlobalDnsProviders(namespace.GlobalNamespace).Controller().Lister(),
	}
	return n
}

//sync is called periodically and on real updates
func (n *GDController) sync(key string, obj *v3.GlobalDns) (runtime.Object, error) {
	if obj == nil || obj.DeletionTimestamp != nil {
		return nil, nil
	}

	metaAccessor, err := meta.Accessor(obj)
	if err != nil {
		return nil, err
	}
	creatorID, ok := metaAccessor.GetAnnotations()[rbac.CreatorIDAnn]
	if !ok {
		return nil, fmt.Errorf("GlobalDNS %v has no creatorId annotation", metaAccessor.GetName())
	}

	if err := rbac.CreateRoleAndRoleBinding(rbac.GlobalDNSResource, v3.GlobalDnsGroupVersionKind.Kind, obj.Name, namespace.GlobalNamespace,
		rbac.RancherManagementAPIVersion, creatorID, []string{rbac.RancherManagementAPIGroup},
		obj.UID, obj.Spec.Members, n.managementContext); err != nil {
		return nil, err
	}
	//check if status.endpoints is set, if yes create a dummy ingress if not already present
	//if ingress exists, update endpoints if different

	var isUpdate bool

	//check if ingress for this globaldns is already present
	ingress, err := n.getIngressForGlobalDNS(obj)

	if err != nil && !k8serrors.IsNotFound(err) {
		return nil, fmt.Errorf("GlobalDNSController: Error listing ingress for the GlobalDNS %v", err)
	}

	if ingress != nil && err == nil {
		isUpdate = true
	}

	if len(obj.Status.Endpoints) == 0 && !isUpdate {
		return nil, nil
	}

	if !isUpdate {
		ingress, err = n.createIngressForGlobalDNS(obj)
		if err != nil {
			return nil, fmt.Errorf("GlobalDNSController: Error creating an ingress for the GlobalDNS %v", err)
		}
	}

	err = n.updateIngressForDNS(ingress, obj)
	if err != nil {
		return nil, fmt.Errorf("GlobalDNSController: Error updating ingress for the GlobalDNS %v", err)
	}

	return nil, nil
}

func (n *GDController) getIngressForGlobalDNS(globaldns *v3.GlobalDns) (*v1beta1.Ingress, error) {
	ingress, err := n.ingresses.Get(context.TODO(), strings.Join([]string{"globaldns-ingress", globaldns.Name}, "-"), metav1.GetOptions{}) //n.Get("", strings.Join([]string{"globaldns-ingress", globaldns.Name}, "-"))
	if err != nil {
		return nil, err
	}
	//make sure the ingress is owned by this globalDNS
	if n.isIngressOwnedByGlobalDNS(ingress, globaldns) {
		return ingress, nil
	}
	return nil, nil
}

func (n *GDController) isIngressOwnedByGlobalDNS(ingress *v1beta1.Ingress, globaldns *v3.GlobalDns) bool {
	for i, owners := 0, ingress.GetOwnerReferences(); owners != nil && i < len(owners); i++ {
		if owners[i].UID == globaldns.UID && owners[i].Kind == globaldns.Kind {
			return true
		}
	}
	return false
}

func (n *GDController) createIngressForGlobalDNS(globaldns *v3.GlobalDns) (*v1beta1.Ingress, error) {
	ingressSpec := n.generateNewIngressSpec(globaldns)
	if globaldns.Spec.TTL != 0 {
		ingressSpec.ObjectMeta.Annotations[annotationDNSTTL] = strconv.FormatInt(globaldns.Spec.TTL, 10)
	}
	if globaldns.Spec.ProviderName != "" {
		ingressClass, err := n.getIngressClass(globaldns.Spec.ProviderName)
		if err != nil {
			return nil, err
		}
		if ingressClass != "" {
			ingressSpec.ObjectMeta.Annotations[annotationIngressClass] = ingressClass
		}
	}
	ingressObj, err := n.ingresses.Create(context.TODO(), ingressSpec, metav1.CreateOptions{})
	if err != nil {
		return nil, err
	}
	logrus.Infof("Created ingress %v for globalDNS %s", ingressObj.Name, globaldns.Name)
	return ingressObj, nil
}

func (n *GDController) generateNewIngressSpec(globaldns *v3.GlobalDns) *v1beta1.Ingress {
	controller := true
	return &v1beta1.Ingress{
		ObjectMeta: metav1.ObjectMeta{
			Name: strings.Join([]string{"globaldns-ingress", globaldns.Name}, "-"),
			OwnerReferences: []metav1.OwnerReference{
				{
					Name:       globaldns.Name,
					APIVersion: globaldns.APIVersion,
					UID:        globaldns.UID,
					Kind:       globaldns.Kind,
					Controller: &controller,
				},
			},
			Annotations: map[string]string{
				annotationIngressClass: "rancher-external-dns",
			},
			Namespace: globaldns.Namespace,
		},
		Spec: v1beta1.IngressSpec{
			Rules: []v1beta1.IngressRule{
				{
					Host: globaldns.Spec.FQDN,
					IngressRuleValue: v1beta1.IngressRuleValue{
						HTTP: &v1beta1.HTTPIngressRuleValue{
							Paths: []v1beta1.HTTPIngressPath{
								{
									Backend: v1beta1.IngressBackend{
										ServiceName: "http-svc-dummy",
										ServicePort: intstr.IntOrString{
											Type:   intstr.Int,
											IntVal: 42,
										},
									},
								},
							},
						},
					},
				},
			},
		},
	}
}

func (n *GDController) getIngressClass(globalDNSProviderName string) (string, error) {
	providerName, err := n.getGlobalDNSProviderName(globalDNSProviderName)
	if err != nil {
		return defaultIngressClass, err
	}

	provider, err := n.globalDNSProviderLister.Get(namespace.GlobalNamespace, providerName)
	if err != nil && k8serrors.IsNotFound(err) {
		logrus.Errorf("GlobalDNSController: Object Not found Error %v, while listing GlobalDNSProvider by name %v", err, providerName)
		return defaultIngressClass, nil
	}
	if err != nil {
		return defaultIngressClass, fmt.Errorf("GlobalDNSController: Error %v Listing GlobalDNSProvider by name %v", err, providerName)
	}

	var options map[string]string
	if provider.Spec.Route53ProviderConfig != nil {
		options = provider.Spec.Route53ProviderConfig.AdditionalOptions
	} else if provider.Spec.CloudflareProviderConfig != nil {
		options = provider.Spec.CloudflareProviderConfig.AdditionalOptions
	} else if provider.Spec.AlidnsProviderConfig != nil {
		options = provider.Spec.AlidnsProviderConfig.AdditionalOptions
	}

	if options != nil {
		ingressClassAnnotation, ok := options[annotationFilter]
		if ok {
			prefix := annotationIngressClass + "="
			if strings.HasPrefix(ingressClassAnnotation, prefix) {
				return strings.TrimPrefix(ingressClassAnnotation, prefix), nil
			}
		}
	}
	return defaultIngressClass, nil
}

func (n *GDController) getGlobalDNSProviderName(globalDNSProviderName string) (string, error) {
	split := strings.SplitN(globalDNSProviderName, ":", 2)
	if len(split) != 2 {
		return "", fmt.Errorf("error in splitting globalDNSProviderName %v", globalDNSProviderName)
	}
	provider := split[1]
	return provider, nil
}

func (n *GDController) updateIngressForDNS(ingress *v1beta1.Ingress, obj *v3.GlobalDns) error {
	var err error

	if n.ifEndpointsDiffer(ingress.Status.LoadBalancer.Ingress, obj.Status.Endpoints) {
		ingress.Status.LoadBalancer.Ingress = n.sliceToStatus(obj.Status.Endpoints)
		ingress, err = n.ingresses.UpdateStatus(context.TODO(), ingress, metav1.UpdateOptions{})

		if err != nil {
			return fmt.Errorf("GlobalDNSController: Error updating Ingress %v", err)
		}
	}

	var updateIngress bool
	if len(ingress.Spec.Rules) > 0 {
		if !strings.EqualFold(ingress.Spec.Rules[0].Host, obj.Spec.FQDN) {
			ingress.Spec.Rules[0].Host = obj.Spec.FQDN
			updateIngress = true
		}
	}

	ttlvalue := strconv.FormatInt(obj.Spec.TTL, 10)
	if !strings.EqualFold(ingress.ObjectMeta.Annotations[annotationDNSTTL], ttlvalue) {
		ingress.ObjectMeta.Annotations[annotationDNSTTL] = ttlvalue
		updateIngress = true
	}

	if obj.Spec.ProviderName != "" {
		ingressClass, err := n.getIngressClass(obj.Spec.ProviderName)
		if err != nil {
			return err
		}
		if !strings.EqualFold(ingress.ObjectMeta.Annotations[annotationIngressClass], ingressClass) {
			ingress.ObjectMeta.Annotations[annotationIngressClass] = ingressClass
			updateIngress = true
		}
	}

	if updateIngress {
		_, err = n.ingresses.Update(context.TODO(), ingress, metav1.UpdateOptions{})
		if err != nil {
			return fmt.Errorf("GlobalDNSController: Error updating Ingress %v", err)
		}
	}

	return nil
}

func (n *GDController) ifEndpointsDiffer(ingressEps []apiv1.LoadBalancerIngress, endpoints []string) bool {
	if len(ingressEps) != len(endpoints) {
		return true
	}

	mapIngEndpoints := n.gatherIngressEndpoints(ingressEps)
	for _, ep := range endpoints {
		if !mapIngEndpoints[ep] {
			return true
		}
	}
	return false
}

func (n *GDController) gatherIngressEndpoints(ingressEps []apiv1.LoadBalancerIngress) map[string]bool {
	mapIngEndpoints := make(map[string]bool)
	for _, ep := range ingressEps {
		if ep.IP != "" {
			mapIngEndpoints[ep.IP] = true
		} else if ep.Hostname != "" {
			mapIngEndpoints[ep.Hostname] = true
		}
	}
	return mapIngEndpoints
}

// sliceToStatus converts a slice of IP and/or hostnames to LoadBalancerIngress
func (n *GDController) sliceToStatus(endpoints []string) []apiv1.LoadBalancerIngress {
	lbi := []apiv1.LoadBalancerIngress{}
	for _, ep := range endpoints {
		if net.ParseIP(ep) == nil {
			lbi = append(lbi, apiv1.LoadBalancerIngress{Hostname: ep})
		} else {
			lbi = append(lbi, apiv1.LoadBalancerIngress{IP: ep})
		}
	}
	return lbi
}
<commit_msg>Fix the additionalOption key needed to add annotation-filter param to external-dns<commit_after>package globaldns

import (
	"context"
	"fmt"
	"net"
	"strings"

	"github.com/rancher/rancher/pkg/controllers/management/rbac"
	v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
	"github.com/rancher/rancher/pkg/namespace"
	"github.com/rancher/rancher/pkg/types/config"
	"github.com/sirupsen/logrus"

	"strconv"

	apiv1 "k8s.io/api/core/v1"
	"k8s.io/api/extensions/v1beta1"
	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/intstr"
	clientv1beta1 "k8s.io/client-go/kubernetes/typed/extensions/v1beta1"
)

const (
	GlobaldnsController    = "mgmt-global-dns-controller"
	annotationIngressClass = "kubernetes.io/ingress.class"
	annotationFilter       = "annotationFilter"
	annotationDNSTTL       = "external-dns.alpha.kubernetes.io/ttl"
	defaultIngressClass    = "rancher-external-dns"
)

type GDController struct {
	ingresses               clientv1beta1.IngressInterface //need to use client-go IngressInterface to update Ingress.Status field
	managementContext       *config.ManagementContext
	globalDNSProviderLister v3.GlobalDnsProviderLister
}

func newGlobalDNSController(ctx context.Context, mgmt *config.ManagementContext) *GDController {
	n := &GDController{
		ingresses:               mgmt.K8sClient.ExtensionsV1beta1().Ingresses(namespace.GlobalNamespace),
		managementContext:       mgmt,
		globalDNSProviderLister: mgmt.Management.GlobalDnsProviders(namespace.GlobalNamespace).Controller().Lister(),
	}
	return n
}

//sync is called periodically and on real updates
func (n *GDController) sync(key string, obj *v3.GlobalDns) (runtime.Object, error) {
	if obj == nil || obj.DeletionTimestamp != nil {
		return nil, nil
	}

	metaAccessor, err := meta.Accessor(obj)
	if err != nil {
		return nil, err
	}
	creatorID, ok := metaAccessor.GetAnnotations()[rbac.CreatorIDAnn]
	if !ok {
		return nil, fmt.Errorf("GlobalDNS %v has no creatorId annotation", metaAccessor.GetName())
	}

	if err := rbac.CreateRoleAndRoleBinding(rbac.GlobalDNSResource, v3.GlobalDnsGroupVersionKind.Kind, obj.Name, namespace.GlobalNamespace,
		rbac.RancherManagementAPIVersion, creatorID, []string{rbac.RancherManagementAPIGroup},
		obj.UID, obj.Spec.Members, n.managementContext); err != nil {
		return nil, err
	}
	//check if status.endpoints is set, if yes create a dummy ingress if not already present
	//if ingress exists, update endpoints if different

	var isUpdate bool

	//check if ingress for this globaldns is already present
	ingress, err := n.getIngressForGlobalDNS(obj)

	if err != nil && !k8serrors.IsNotFound(err) {
		return nil, fmt.Errorf("GlobalDNSController: Error listing ingress for the GlobalDNS %v", err)
	}

	if ingress != nil && err == nil {
		isUpdate = true
	}

	if len(obj.Status.Endpoints) == 0 && !isUpdate {
		return nil, nil
	}

	if !isUpdate {
		ingress, err = n.createIngressForGlobalDNS(obj)
		if err != nil {
			return nil, fmt.Errorf("GlobalDNSController: Error creating an ingress for the GlobalDNS %v", err)
		}
	}

	err = n.updateIngressForDNS(ingress, obj)
	if err != nil {
		return nil, fmt.Errorf("GlobalDNSController: Error updating ingress for the GlobalDNS %v", err)
	}

	return nil, nil
}

func (n *GDController) getIngressForGlobalDNS(globaldns *v3.GlobalDns) (*v1beta1.Ingress, error) {
	ingress, err := n.ingresses.Get(context.TODO(), strings.Join([]string{"globaldns-ingress", globaldns.Name}, "-"), metav1.GetOptions{}) //n.Get("", strings.Join([]string{"globaldns-ingress", globaldns.Name}, "-"))
	if err != nil {
		return nil, err
	}
	//make sure the ingress is owned by this globalDNS
	if n.isIngressOwnedByGlobalDNS(ingress, globaldns) {
		return ingress, nil
	}
	return nil, nil
}

func (n *GDController) isIngressOwnedByGlobalDNS(ingress *v1beta1.Ingress, globaldns *v3.GlobalDns) bool {
	for i, owners := 0, ingress.GetOwnerReferences(); owners != nil && i < len(owners); i++ {
		if owners[i].UID == globaldns.UID && owners[i].Kind == globaldns.Kind {
			return true
		}
	}
	return false
}

func (n *GDController) createIngressForGlobalDNS(globaldns *v3.GlobalDns) (*v1beta1.Ingress, error) {
	ingressSpec := n.generateNewIngressSpec(globaldns)
	if globaldns.Spec.TTL != 0 {
		ingressSpec.ObjectMeta.Annotations[annotationDNSTTL] = strconv.FormatInt(globaldns.Spec.TTL, 10)
	}
	if globaldns.Spec.ProviderName != "" {
		ingressClass, err := n.getIngressClass(globaldns.Spec.ProviderName)
		if err != nil {
			return nil, err
		}
		if ingressClass != "" {
			ingressSpec.ObjectMeta.Annotations[annotationIngressClass] = ingressClass
		}
	}
	ingressObj, err := n.ingresses.Create(context.TODO(), ingressSpec, metav1.CreateOptions{})
	if err != nil {
		return nil, err
	}
	logrus.Infof("Created ingress %v for globalDNS %s", ingressObj.Name, globaldns.Name)
	return ingressObj, nil
}

func (n *GDController) generateNewIngressSpec(globaldns *v3.GlobalDns) *v1beta1.Ingress {
	controller := true
	return &v1beta1.Ingress{
		ObjectMeta: metav1.ObjectMeta{
			Name: strings.Join([]string{"globaldns-ingress", globaldns.Name}, "-"),
			OwnerReferences: []metav1.OwnerReference{
				{
					Name:       globaldns.Name,
					APIVersion: globaldns.APIVersion,
					UID:        globaldns.UID,
					Kind:       globaldns.Kind,
					Controller: &controller,
				},
			},
			Annotations: map[string]string{
				annotationIngressClass: "rancher-external-dns",
			},
			Namespace: globaldns.Namespace,
		},
		Spec: v1beta1.IngressSpec{
			Rules: []v1beta1.IngressRule{
				{
					Host: globaldns.Spec.FQDN,
					IngressRuleValue: v1beta1.IngressRuleValue{
						HTTP: &v1beta1.HTTPIngressRuleValue{
							Paths: []v1beta1.HTTPIngressPath{
								{
									Backend: v1beta1.IngressBackend{
										ServiceName: "http-svc-dummy",
										ServicePort: intstr.IntOrString{
											Type:   intstr.Int,
											IntVal: 42,
										},
									},
								},
							},
						},
					},
				},
			},
		},
	}
}

func (n *GDController) getIngressClass(globalDNSProviderName string) (string, error) {
	providerName, err := n.getGlobalDNSProviderName(globalDNSProviderName)
	if err != nil {
		return defaultIngressClass, err
	}

	provider, err := n.globalDNSProviderLister.Get(namespace.GlobalNamespace, providerName)
	if err != nil && k8serrors.IsNotFound(err) {
		logrus.Errorf("GlobalDNSController: Object Not found Error %v, while listing GlobalDNSProvider by name %v", err, providerName)
		return defaultIngressClass, nil
	}
	if err != nil {
		return defaultIngressClass, fmt.Errorf("GlobalDNSController: Error %v Listing GlobalDNSProvider by name %v", err, providerName)
	}

	var options map[string]string
	if provider.Spec.Route53ProviderConfig != nil {
		options = provider.Spec.Route53ProviderConfig.AdditionalOptions
	} else if provider.Spec.CloudflareProviderConfig != nil {
		options = provider.Spec.CloudflareProviderConfig.AdditionalOptions
	} else if provider.Spec.AlidnsProviderConfig != nil {
		options = provider.Spec.AlidnsProviderConfig.AdditionalOptions
	}

	if options != nil {
		ingressClassAnnotation, ok := options[annotationFilter]
		if ok {
			prefix := annotationIngressClass + "="
			if strings.HasPrefix(ingressClassAnnotation, prefix) {
				return strings.TrimPrefix(ingressClassAnnotation, prefix), nil
			}
		}
	}
	return defaultIngressClass, nil
}

func (n *GDController) getGlobalDNSProviderName(globalDNSProviderName string) (string, error) {
	split := strings.SplitN(globalDNSProviderName, ":", 2)
	if len(split) != 2 {
		return "", fmt.Errorf("error in splitting globalDNSProviderName %v", globalDNSProviderName)
	}
	provider := split[1]
	return provider, nil
}

func (n *GDController) updateIngressForDNS(ingress *v1beta1.Ingress, obj *v3.GlobalDns) error {
	var err error

	if n.ifEndpointsDiffer(ingress.Status.LoadBalancer.Ingress, obj.Status.Endpoints) {
		ingress.Status.LoadBalancer.Ingress = n.sliceToStatus(obj.Status.Endpoints)
		ingress, err = n.ingresses.UpdateStatus(context.TODO(), ingress, metav1.UpdateOptions{})

		if err != nil {
			return fmt.Errorf("GlobalDNSController: Error updating Ingress %v", err)
		}
	}

	var updateIngress bool
	if len(ingress.Spec.Rules) > 0 {
		if !strings.EqualFold(ingress.Spec.Rules[0].Host, obj.Spec.FQDN) {
			ingress.Spec.Rules[0].Host = obj.Spec.FQDN
			updateIngress = true
		}
	}

	ttlvalue := strconv.FormatInt(obj.Spec.TTL, 10)
	if !strings.EqualFold(ingress.ObjectMeta.Annotations[annotationDNSTTL], ttlvalue) {
		ingress.ObjectMeta.Annotations[annotationDNSTTL] = ttlvalue
		updateIngress = true
	}

	if obj.Spec.ProviderName != "" {
		ingressClass, err := n.getIngressClass(obj.Spec.ProviderName)
		if err != nil {
			return err
		}
		if !strings.EqualFold(ingress.ObjectMeta.Annotations[annotationIngressClass], ingressClass) {
			ingress.ObjectMeta.Annotations[annotationIngressClass] = ingressClass
			updateIngress = true
		}
	}

	if updateIngress {
		_, err = n.ingresses.Update(context.TODO(), ingress, metav1.UpdateOptions{})
		if err != nil {
			return fmt.Errorf("GlobalDNSController: Error updating Ingress %v", err)
		}
	}

	return nil
}

func (n *GDController) ifEndpointsDiffer(ingressEps []apiv1.LoadBalancerIngress, endpoints []string) bool {
	if len(ingressEps) != len(endpoints) {
		return true
	}

	mapIngEndpoints := n.gatherIngressEndpoints(ingressEps)
	for _, ep := range endpoints {
		if !mapIngEndpoints[ep] {
			return true
		}
	}
	return false
}

func (n *GDController) gatherIngressEndpoints(ingressEps []apiv1.LoadBalancerIngress) map[string]bool {
	mapIngEndpoints := make(map[string]bool)
	for _, ep := range ingressEps {
		if ep.IP != "" {
			mapIngEndpoints[ep.IP] = true
		} else if ep.Hostname != "" {
			mapIngEndpoints[ep.Hostname] = true
		}
	}
	return mapIngEndpoints
}

// sliceToStatus converts a slice of IP and/or hostnames to LoadBalancerIngress
func (n *GDController) sliceToStatus(endpoints []string) []apiv1.LoadBalancerIngress {
	lbi := []apiv1.LoadBalancerIngress{}
	for _, ep := range endpoints {
		if net.ParseIP(ep) == nil {
			lbi = append(lbi, apiv1.LoadBalancerIngress{Hostname: ep})
		} else {
			lbi = append(lbi, apiv1.LoadBalancerIngress{IP: ep})
		}
	}
	return lbi
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"runtime"
	"sync"

	"github.com/Shopify/sarama"
	"github.com/vmihailenco/msgpack"
)

type Log struct {
	UID       string
	Type      string
	Level     string
	Host      string
	Timestamp string
	Data      map[string]interface{}
}

func KafkaMessages(servers []string, topic string, offset int64) <-chan interface{} {
	out := make(chan interface{})

	go func() {
		defer close(out)

		consumer := MustSucceed(sarama.NewConsumer(servers, nil)).(sarama.Consumer)
		defer consumer.Close()

		partitions := MustSucceed(consumer.Partitions(topic)).([]int32)
		wg := new(sync.WaitGroup)
		defer wg.Wait()

		for _, p := range partitions {
			wg.Add(1)

			go func() {
				defer wg.Done()

				pc := MustSucceed(consumer.ConsumePartition(topic, p, offset)).(sarama.PartitionConsumer)
				defer pc.Close()

				for msg := range pc.Messages() {
					if true {
						fmt.Println(string(msg.Value))
					}
					out <- string(msg.Value)
				}
			}()
		}
	}()

	return out
}

func MustSucceed(args ...interface{}) interface{} {
	if len(args) == 0 {
		return nil
	}

	if err := args[len(args)-1]; err != nil {
		log.Fatal(err)
	}

	if len(args) > 1 {
		return args[0]
	}

	return nil
}

func psink(in <-chan interface{}) {
	wg := new(sync.WaitGroup)
	defer wg.Wait()

	for i := 0; i < runtime.NumCPU(); i++ {
		wg.Add(1)

		go func() {
			defer wg.Done()

			for msg := range in {
				fmt.Println("here", msg)
				//log := parseLog(msg)
			}
		}()
	}
}

func parseLog(msg interface{}) Log {
	k, _ := msg.([]byte)
	var item Log
	msgpack.Unmarshal(k, &item)
	return item
}

func main() {

	// initialize with empty data or an actual slice of floats

	brokers := []string{"10.50.21.117:9094", "10.50.21.118:9094", "10.50.21.119:9094"}
	topic := "test"

	wg := new(sync.WaitGroup)
	defer wg.Wait()

	wg.Add(1)

	go func() {
		defer wg.Done()
		psink(KafkaMessages(brokers, topic, int64(-1)))
	}()

}
<commit_msg>updated consumer<commit_after>package main

import (
	"fmt"
	"log"
	"runtime"
	"sync"

	"github.com/Shopify/sarama"
	"github.com/vmihailenco/msgpack"
)

type Log struct {
	UID       string
	Type      string
	Level     string
	Host      string
	Timestamp string
	Data      map[string]interface{}
}

func KafkaMessages(servers []string, topic string, offset int64) <-chan interface{} {
	out := make(chan interface{})

	go func() {
		defer close(out)

		consumer := MustSucceed(sarama.NewConsumer(servers, nil)).(sarama.Consumer)
		defer consumer.Close()

		partitions := MustSucceed(consumer.Partitions(topic)).([]int32)
		wg := new(sync.WaitGroup)
		defer wg.Wait()

		for _, p := range partitions {
			wg.Add(1)

			go func() {
				defer wg.Done()

				pc := MustSucceed(consumer.ConsumePartition(topic, p, offset)).(sarama.PartitionConsumer)
				defer pc.Close()

				for msg := range pc.Messages() {
					if true {
						fmt.Println(string(msg.Value))
					}
					out <- string(msg.Value)
				}
			}()
		}
	}()

	return out
}

func MustSucceed(args ...interface{}) interface{} {
	if len(args) == 0 {
		return nil
	}

	if err := args[len(args)-1]; err != nil {
		log.Fatal(err)
	}

	if len(args) > 1 {
		return args[0]
	}

	return nil
}

func psink(in <-chan interface{}) {
	wg := new(sync.WaitGroup)
	defer wg.Wait()

	for i := 0; i < runtime.NumCPU(); i++ {
		wg.Add(1)

		go func() {
			defer wg.Done()

			for msg := range in {
				fmt.Println("here", msg)
				//log := parseLog(msg)
			}
		}()
	}
}

func parseLog(msg interface{}) Log {
	k, _ := msg.([]byte)
	var item Log
	msgpack.Unmarshal(k, &item)
	return item
}

func main() {

	brokers := []string{"10.50.21.117:9094", "10.50.21.118:9094", "10.50.21.119:9094"}
	topic := "test"

	wg := new(sync.WaitGroup)
	defer wg.Wait()

	wg.Add(1)

	go func() {
		defer wg.Done()
		psink(KafkaMessages(brokers, topic, int64(-1)))
	}()

}
<|endoftext|>