<commit_before>package tui

import (
	"bytes"
	"image"
	"testing"
)

func TestMask_Full(t *testing.T) {
	surface := newTestSurface(10, 10)

	p := NewPainter(surface, NewTheme())
	p.WithMask(image.Rect(0, 0, 10, 10), func(p *Painter) {
		p.WithMask(image.Rect(0, 0, 10, 10), func(p *Painter) {
			sz := p.surface.Size()
			for x := 0; x < sz.X; x++ {
				for y := 0; y < sz.Y; y++ {
					p.DrawRune(x, y, '█')
				}
			}
		})
	})

	want := `
██████████
██████████
██████████
██████████
██████████
██████████
██████████
██████████
██████████
██████████
`
	if surface.String() != want {
		t.Errorf("got = \n%s\n\nwant = \n%s", surface.String(), want)
	}
}

func TestMask_Inset(t *testing.T) {
	surface := newTestSurface(10, 10)

	p := NewPainter(surface, NewTheme())
	p.WithMask(image.Rect(0, 0, 10, 10), func(p *Painter) {
		p.WithMask(image.Rect(1, 1, 9, 9), func(p *Painter) {
			sz := p.surface.Size()
			for x := 0; x < sz.X; x++ {
				for y := 0; y < sz.Y; y++ {
					p.DrawRune(x, y, '█')
				}
			}
		})
	})

	want := `
..........
.████████.
.████████.
.████████.
.████████.
.████████.
.████████.
.████████.
.████████.
..........
`
	if surface.String() != want {
		t.Errorf("got = \n%s\n\nwant = \n%s", surface.String(), want)
	}
}

func TestMask_FirstCell(t *testing.T) {
	surface := newTestSurface(10, 10)

	p := NewPainter(surface, NewTheme())
	p.WithMask(image.Rect(0, 0, 10, 10), func(p *Painter) {
		p.WithMask(image.Rect(0, 0, 1, 1), func(p *Painter) {
			sz := p.surface.Size()
			for x := 0; x < sz.X; x++ {
				for y := 0; y < sz.Y; y++ {
					p.DrawRune(x, y, '█')
				}
			}
		})
	})

	want := `
█.........
..........
..........
..........
..........
..........
..........
..........
..........
..........
`
	if surface.String() != want {
		t.Errorf("got = \n%s\n\nwant = \n%s", surface.String(), want)
	}
}

func TestMask_LastCell(t *testing.T) {
	surface := newTestSurface(10, 10)

	p := NewPainter(surface, NewTheme())
	p.WithMask(image.Rect(0, 0, 10, 10), func(p *Painter) {
		p.WithMask(image.Rect(9, 9, 10, 10), func(p *Painter) {
			sz := p.surface.Size()
			for x := 0; x < sz.X; x++ {
				for y := 0; y < sz.Y; y++ {
					p.DrawRune(x, y, '█')
				}
			}
		})
	})

	want := `
..........
..........
..........
..........
..........
..........
..........
..........
..........
.........█
`
	if surface.String() != want {
		t.Errorf("got = \n%s\n\nwant = \n%s", surface.String(), want)
	}
}

func TestMask_MaskWithinEmptyMaskIsHidden(t *testing.T) {
	surface := newTestSurface(10, 10)

	p := NewPainter(surface, NewTheme())
	p.WithMask(image.Rect(0, 0, 0, 0), func(p *Painter) {
		p.WithMask(image.Rect(1, 1, 9, 9), func(p *Painter) {
			sz := p.surface.Size()
			for x := 0; x < sz.X; x++ {
				for y := 0; y < sz.Y; y++ {
					p.DrawRune(x, y, '█')
				}
			}
		})
	})

	want := `
..........
..........
..........
..........
..........
..........
..........
..........
..........
..........
`
	if surface.String() != want {
		t.Errorf("got = \n%s\n\nwant = \n%s", surface.String(), want)
	}
}

type testCell struct {
	Rune  rune
	Style Style
}

type testSurface struct {
	cells   map[image.Point]testCell
	cursor  image.Point
	size    image.Point
	emptyCh rune
}

func newTestSurface(w, h int) *testSurface {
	return &testSurface{
		cells:   make(map[image.Point]testCell),
		size:    image.Point{w, h},
		emptyCh: '.',
	}
}

func (s *testSurface) SetCell(x, y int, ch rune, style Style) {
	s.cells[image.Point{x, y}] = testCell{
		Rune:  ch,
		Style: style,
	}
}

func (s *testSurface) SetCursor(x, y int) {
	s.cursor = image.Point{x, y}
}

func (s *testSurface) HideCursor() {
	s.cursor = image.Point{}
}

func (s *testSurface) Begin() {
	s.cells = make(map[image.Point]testCell)
}

func (s *testSurface) End() {
	// NOP
}

func (s *testSurface) Size() image.Point {
	return s.size
}

// String writes the testSurface's characters as a string.
func (s *testSurface) String() string {
	var buf bytes.Buffer
	buf.WriteRune('\n')
	for j := 0; j < s.size.Y; j++ {
		for i := 0; i < s.size.X; i++ {
			if cell, ok := s.cells[image.Point{i, j}]; ok {
				buf.WriteRune(cell.Rune)
				if w := runeWidth(cell.Rune); w > 1 {
					i += w - 1
				}
			} else {
				buf.WriteRune(s.emptyCh)
			}
		}
		buf.WriteRune('\n')
	}
	return buf.String()
}

// FgColors renders the testSurface's foreground colors, using the digit 0-7 for painted cells.
func (s *testSurface) FgColors() string {
	var buf bytes.Buffer
	buf.WriteRune('\n')
	for j := 0; j < s.size.Y; j++ {
		for i := 0; i < s.size.X; i++ {
			if cell, ok := s.cells[image.Point{i, j}]; ok {
				color := cell.Style.Fg
				if cell.Style.Reverse {
					color = cell.Style.Bg
				}
				buf.WriteRune('0' + rune(color))
			} else {
				buf.WriteRune(s.emptyCh)
			}
		}
		buf.WriteRune('\n')
	}
	return buf.String()
}

// BgColors renders the testSurface's background colors, using the digit 0-7 for painted cells.
func (s *testSurface) BgColors() string {
	var buf bytes.Buffer
	buf.WriteRune('\n')
	for j := 0; j < s.size.Y; j++ {
		for i := 0; i < s.size.X; i++ {
			if cell, ok := s.cells[image.Point{i, j}]; ok {
				color := cell.Style.Bg
				if cell.Style.Reverse {
					color = cell.Style.Fg
				}
				buf.WriteRune('0' + rune(color))
			} else {
				buf.WriteRune(s.emptyCh)
			}
		}
		buf.WriteRune('\n')
	}
	return buf.String()
}
<commit_msg>Add failing test for painter style.<commit_after>package tui

import (
	"bytes"
	"image"
	"testing"
)

func TestMask_Full(t *testing.T) {
	surface := newTestSurface(10, 10)

	p := NewPainter(surface, NewTheme())
	p.WithMask(image.Rect(0, 0, 10, 10), func(p *Painter) {
		p.WithMask(image.Rect(0, 0, 10, 10), func(p *Painter) {
			sz := p.surface.Size()
			for x := 0; x < sz.X; x++ {
				for y := 0; y < sz.Y; y++ {
					p.DrawRune(x, y, '█')
				}
			}
		})
	})

	want := `
██████████
██████████
██████████
██████████
██████████
██████████
██████████
██████████
██████████
██████████
`
	if surface.String() != want {
		t.Errorf("got = \n%s\n\nwant = \n%s", surface.String(), want)
	}
}

func TestMask_Inset(t *testing.T) {
	surface := newTestSurface(10, 10)

	p := NewPainter(surface, NewTheme())
	p.WithMask(image.Rect(0, 0, 10, 10), func(p *Painter) {
		p.WithMask(image.Rect(1, 1, 9, 9), func(p *Painter) {
			sz := p.surface.Size()
			for x := 0; x < sz.X; x++ {
				for y := 0; y < sz.Y; y++ {
					p.DrawRune(x, y, '█')
				}
			}
		})
	})

	want := `
..........
.████████.
.████████.
.████████.
.████████.
.████████.
.████████.
.████████.
.████████.
..........
`
	if surface.String() != want {
		t.Errorf("got = \n%s\n\nwant = \n%s", surface.String(), want)
	}
}

func TestMask_FirstCell(t *testing.T) {
	surface := newTestSurface(10, 10)

	p := NewPainter(surface, NewTheme())
	p.WithMask(image.Rect(0, 0, 10, 10), func(p *Painter) {
		p.WithMask(image.Rect(0, 0, 1, 1), func(p *Painter) {
			sz := p.surface.Size()
			for x := 0; x < sz.X; x++ {
				for y := 0; y < sz.Y; y++ {
					p.DrawRune(x, y, '█')
				}
			}
		})
	})

	want := `
█.........
..........
..........
..........
..........
..........
..........
..........
..........
..........
`
	if surface.String() != want {
		t.Errorf("got = \n%s\n\nwant = \n%s", surface.String(), want)
	}
}

func TestMask_LastCell(t *testing.T) {
	surface := newTestSurface(10, 10)

	p := NewPainter(surface, NewTheme())
	p.WithMask(image.Rect(0, 0, 10, 10), func(p *Painter) {
		p.WithMask(image.Rect(9, 9, 10, 10), func(p *Painter) {
			sz := p.surface.Size()
			for x := 0; x < sz.X; x++ {
				for y := 0; y < sz.Y; y++ {
					p.DrawRune(x, y, '█')
				}
			}
		})
	})

	want := `
..........
..........
..........
..........
..........
..........
..........
..........
..........
.........█
`
	if surface.String() != want {
		t.Errorf("got = \n%s\n\nwant = \n%s", surface.String(), want)
	}
}

func TestMask_MaskWithinEmptyMaskIsHidden(t *testing.T) {
	surface := newTestSurface(10, 10)

	p := NewPainter(surface, NewTheme())
	p.WithMask(image.Rect(0, 0, 0, 0), func(p *Painter) {
		p.WithMask(image.Rect(1, 1, 9, 9), func(p *Painter) {
			sz := p.surface.Size()
			for x := 0; x < sz.X; x++ {
				for y := 0; y < sz.Y; y++ {
					p.DrawRune(x, y, '█')
				}
			}
		})
	})

	want := `
..........
..........
..........
..........
..........
..........
..........
..........
..........
..........
`
	if surface.String() != want {
		t.Errorf("got = \n%s\n\nwant = \n%s", surface.String(), want)
	}
}

func TestWithStyle_ApplyStyle(t *testing.T) {
	surface := newTestSurface(5, 5)

	theme := NewTheme()
	theme.SetStyle("explicit", Style{Fg: ColorWhite, Bg: ColorBlack})

	p := NewPainter(surface, theme)
	p.WithMask(image.Rect(0, 0, 5, 5), func(p *Painter) {
		p.WithMask(image.Rect(1, 1, 4, 4), func(p *Painter) {
			sz := p.surface.Size()
			for x := 0; x < sz.X; x++ {
				for y := 0; y < sz.Y; y++ {
					p.DrawRune(x, y, ' ')
				}
			}

			p.WithMask(image.Rect(2, 2, 4, 4), func(p *Painter) {
				p.WithStyle("explicit", func(p *Painter) {
					sz := p.surface.Size()
					for x := 0; x < sz.X; x++ {
						for y := 0; y < sz.Y; y++ {
							p.DrawRune(x, y, '!')
						}
					}

				})
			})
		})
	})

	wantFg := `
.....
.000.
.022.
.022.
.....
`

	wantBg := `
.....
.000.
.011.
.011.
.....
`

	if surface.FgColors() != wantFg {
		t.Errorf("got = \n%s\n\nwant = \n%s", surface.FgColors(), wantFg)
	}
	if surface.BgColors() != wantBg {
		t.Errorf("got = \n%s\n\nwant = \n%s", surface.BgColors(), wantBg)
	}

}

func TestWithStyle_Stacks(t *testing.T) {
	surface := newTestSurface(10, 10)

	theme := NewTheme()
	theme.SetStyle("explicit", Style{Fg: Color(3)})
	theme.SetStyle("auxiliary", Style{Fg: Color(2)})

	p := NewPainter(surface, theme)
	p.WithMask(image.Rect(0, 0, 10, 10), func(p *Painter) {

		// Set "explicit" and draw upper-left and upper-right.
		p.WithStyle("explicit", func(p *Painter) {
			p.WithMask(image.Rect(1, 1, 4, 4), func(p *Painter) {
				sz := p.surface.Size()
				for x := 0; x < sz.X; x++ {
					for y := 0; y < sz.Y; y++ {
						p.DrawRune(x, y, ' ')
					}
				}
			})
			// set "auxiliary" before drawing upper-right.
			p.WithStyle("auxiliary", func(p *Painter) {
				p.WithMask(image.Rect(7, 1, 9, 3), func(p *Painter) {
					sz := p.surface.Size()
					for x := 0; x < sz.X; x++ {
						for y := 0; y < sz.Y; y++ {
							p.DrawRune(x, y, ' ')
						}
					}
				})
			})
			// Then draw bottom-right, falling back to "explicit".
			p.WithMask(image.Rect(1, 6, 4, 9), func(p *Painter) {
				sz := p.surface.Size()
				for x := 0; x < sz.X; x++ {
					for y := 0; y < sz.Y; y++ {
						p.DrawRune(x, y, ' ')
					}
				}
			})
		})

		// Use global default for bottom-right.
		p.WithMask(image.Rect(6, 6, 9, 9), func(p *Painter) {
			sz := p.surface.Size()
			for x := 0; x < sz.X; x++ {
				for y := 0; y < sz.Y; y++ {
					p.DrawRune(x, y, ' ')
				}
			}
		})
	})

	wantFg := `
..........
.333...22.
.333...22.
.333......
..........
..........
.333..000.
.333..000.
.333..000.
..........
`

	if surface.FgColors() != wantFg {
		t.Errorf("got = \n%s\n\nwant = \n%s", surface.FgColors(), wantFg)
	}
}

type testCell struct {
	Rune  rune
	Style Style
}

type testSurface struct {
	cells   map[image.Point]testCell
	cursor  image.Point
	size    image.Point
	emptyCh rune
}

func newTestSurface(w, h int) *testSurface {
	return &testSurface{
		cells:   make(map[image.Point]testCell),
		size:    image.Point{w, h},
		emptyCh: '.',
	}
}

func (s *testSurface) SetCell(x, y int, ch rune, style Style) {
	s.cells[image.Point{x, y}] = testCell{
		Rune:  ch,
		Style: style,
	}
}

func (s *testSurface) SetCursor(x, y int) {
	s.cursor = image.Point{x, y}
}

func (s *testSurface) HideCursor() {
	s.cursor = image.Point{}
}

func (s *testSurface) Begin() {
	s.cells = make(map[image.Point]testCell)
}

func (s *testSurface) End() {
	// NOP
}

func (s *testSurface) Size() image.Point {
	return s.size
}

// String writes the testSurface's characters as a string.
func (s *testSurface) String() string {
	var buf bytes.Buffer
	buf.WriteRune('\n')
	for j := 0; j < s.size.Y; j++ {
		for i := 0; i < s.size.X; i++ {
			if cell, ok := s.cells[image.Point{i, j}]; ok {
				buf.WriteRune(cell.Rune)
				if w := runeWidth(cell.Rune); w > 1 {
					i += w - 1
				}
			} else {
				buf.WriteRune(s.emptyCh)
			}
		}
		buf.WriteRune('\n')
	}
	return buf.String()
}

// FgColors renders the testSurface's foreground colors, using the digit 0-7 for painted cells.
func (s *testSurface) FgColors() string {
	var buf bytes.Buffer
	buf.WriteRune('\n')
	for j := 0; j < s.size.Y; j++ {
		for i := 0; i < s.size.X; i++ {
			if cell, ok := s.cells[image.Point{i, j}]; ok {
				color := cell.Style.Fg
				if cell.Style.Reverse {
					color = cell.Style.Bg
				}
				buf.WriteRune('0' + rune(color))
			} else {
				buf.WriteRune(s.emptyCh)
			}
		}
		buf.WriteRune('\n')
	}
	return buf.String()
}

// BgColors renders the testSurface's background colors, using the digit 0-7 for painted cells.
func (s *testSurface) BgColors() string {
	var buf bytes.Buffer
	buf.WriteRune('\n')
	for j := 0; j < s.size.Y; j++ {
		for i := 0; i < s.size.X; i++ {
			if cell, ok := s.cells[image.Point{i, j}]; ok {
				color := cell.Style.Bg
				if cell.Style.Reverse {
					color = cell.Style.Fg
				}
				buf.WriteRune('0' + rune(color))
			} else {
				buf.WriteRune(s.emptyCh)
			}
		}
		buf.WriteRune('\n')
	}
	return buf.String()
}
<|endoftext|>


<commit_before>package elasticsearch

//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.

// Result is a nested struct in elasticsearch response
type Result struct {
	Enable                    bool                             `json:"enable" xml:"enable"`
	KibanaPort                int                              `json:"kibanaPort" xml:"kibanaPort"`
	QuartzRegex               string                           `json:"quartzRegex" xml:"quartzRegex"`
	CreateUrl                 string                           `json:"createUrl" xml:"createUrl"`
	PublicDomain              string                           `json:"publicDomain" xml:"publicDomain"`
	KibanaDomain              string                           `json:"kibanaDomain" xml:"kibanaDomain"`
	Domain                    string                           `json:"domain" xml:"domain"`
	PaymentType               string                           `json:"paymentType" xml:"paymentType"`
	RegionId                  string                           `json:"regionId" xml:"regionId"`
	UpdatedAt                 string                           `json:"updatedAt" xml:"updatedAt"`
	Env                       string                           `json:"env" xml:"env"`
	NodeAmount                int                              `json:"nodeAmount" xml:"nodeAmount"`
	InstanceId                string                           `json:"instanceId" xml:"instanceId"`
	Status                    string                           `json:"status" xml:"status"`
	Description               string                           `json:"description" xml:"description"`
	EnablePublic              bool                             `json:"enablePublic" xml:"enablePublic"`
	EsVersion                 string                           `json:"esVersion" xml:"esVersion"`
	CreatedAt                 string                           `json:"createdAt" xml:"createdAt"`
	Id                        string                           `json:"id" xml:"id"`
	PublicPort                int                              `json:"publicPort" xml:"publicPort"`
	EsIPWhitelist             []string                         `json:"esIPWhitelist" xml:"esIPWhitelist"`
	KibanaIPWhitelist         []string                         `json:"kibanaIPWhitelist" xml:"kibanaIPWhitelist"`
	PublicIpWhitelist         []string                         `json:"publicIpWhitelist" xml:"publicIpWhitelist"`
	EsIPBlacklist             []string                         `json:"esIPBlacklist" xml:"esIPBlacklist"`
	PrivateNetworkIpWhiteList []string                         `json:"privateNetworkIpWhiteList" xml:"privateNetworkIpWhiteList"`
	EsVersions                []string                         `json:"esVersions" xml:"esVersions"`
	Zones                     []string                         `json:"zones" xml:"zones"`
	NetworkConfig             NetworkConfig                    `json:"networkConfig" xml:"networkConfig"`
	Node                      Node                             `json:"node" xml:"node"`
	MasterConfiguration       MasterConfiguration              `json:"masterConfiguration" xml:"masterConfiguration"`
	NodeSpec                  NodeSpec                         `json:"nodeSpec" xml:"nodeSpec"`
	KibanaConfiguration       KibanaConfiguration              `json:"kibanaConfiguration" xml:"kibanaConfiguration"`
	DataDiskList              []DataDiskListItem               `json:"dataDiskList" xml:"dataDiskList"`
	EsVersionsLatestList      []EsVersionsLatestListItem       `json:"esVersionsLatestList" xml:"esVersionsLatestList"`
	NodeSpecList              []NodeSpecListItem               `json:"nodeSpecList" xml:"nodeSpecList"`
	SynonymsDicts             SynonymsDictsInMoveResourceGroup `json:"synonymsDicts" xml:"synonymsDicts"`
	DictList                  DictListInMoveResourceGroup      `json:"dictList" xml:"dictList"`
}
<commit_msg>fix: ummarshal error of elasticsearch<commit_after>package elasticsearch

//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.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.

// Result is a nested struct in elasticsearch response
type Result struct {
	Enable                    bool                       `json:"enable" xml:"enable"`
	KibanaPort                int                        `json:"kibanaPort" xml:"kibanaPort"`
	QuartzRegex               string                     `json:"quartzRegex" xml:"quartzRegex"`
	CreateUrl                 string                     `json:"createUrl" xml:"createUrl"`
	PublicDomain              string                     `json:"publicDomain" xml:"publicDomain"`
	KibanaDomain              string                     `json:"kibanaDomain" xml:"kibanaDomain"`
	Domain                    string                     `json:"domain" xml:"domain"`
	PaymentType               string                     `json:"paymentType" xml:"paymentType"`
	RegionId                  string                     `json:"regionId" xml:"regionId"`
	UpdatedAt                 string                     `json:"updatedAt" xml:"updatedAt"`
	Env                       string                     `json:"env" xml:"env"`
	NodeAmount                int                        `json:"nodeAmount" xml:"nodeAmount"`
	InstanceId                string                     `json:"instanceId" xml:"instanceId"`
	Status                    string                     `json:"status" xml:"status"`
	Description               string                     `json:"description" xml:"description"`
	EnablePublic              bool                       `json:"enablePublic" xml:"enablePublic"`
	EsVersion                 string                     `json:"esVersion" xml:"esVersion"`
	CreatedAt                 string                     `json:"createdAt" xml:"createdAt"`
	Id                        string                     `json:"id" xml:"id"`
	PublicPort                int                        `json:"publicPort" xml:"publicPort"`
	EsIPWhitelist             []string                   `json:"esIPWhitelist" xml:"esIPWhitelist"`
	KibanaIPWhitelist         []string                   `json:"kibanaIPWhitelist" xml:"kibanaIPWhitelist"`
	PublicIpWhitelist         []string                   `json:"publicIpWhitelist" xml:"publicIpWhitelist"`
	EsIPBlacklist             []string                   `json:"esIPBlacklist" xml:"esIPBlacklist"`
	PrivateNetworkIpWhiteList []string                   `json:"privateNetworkIpWhiteList" xml:"privateNetworkIpWhiteList"`
	EsVersions                []string                   `json:"esVersions" xml:"esVersions"`
	Zones                     []string                   `json:"zones" xml:"zones"`
	NetworkConfig             NetworkConfig              `json:"networkConfig" xml:"networkConfig"`
	Node                      Node                       `json:"node" xml:"node"`
	MasterConfiguration       MasterConfiguration        `json:"masterConfiguration" xml:"masterConfiguration"`
	NodeSpec                  NodeSpec                   `json:"nodeSpec" xml:"nodeSpec"`
	KibanaConfiguration       KibanaConfiguration        `json:"kibanaConfiguration" xml:"kibanaConfiguration"`
	DataDiskList              []DataDiskListItem         `json:"dataDiskList" xml:"dataDiskList"`
	EsVersionsLatestList      []EsVersionsLatestListItem `json:"esVersionsLatestList" xml:"esVersionsLatestList"`
	NodeSpecList              []NodeSpecListItem         `json:"nodeSpecList" xml:"nodeSpecList"`
	SynonymsDicts             []SynonymsDicts            `json:"synonymsDicts" xml:"synonymsDicts"`
	DictList                  []DictList                 `json:"dictList" xml:"dictList"`
}
<|endoftext|>


<commit_before>package persister

/*
Schemas read code from https://github.com/grobian/carbonwriter/
*/

import (
	"regexp"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/alyu/configparser"
	"github.com/lomik/go-whisper"
)

type whisperAggregationItem struct {
	name                 string
	pattern              *regexp.Regexp
	xFilesFactor         float64
	aggregationMethodStr string
	aggregationMethod    whisper.AggregationMethod
}

// WhisperAggregation ...
type WhisperAggregation struct {
	Data    []*whisperAggregationItem
	Default *whisperAggregationItem
}

// NewWhisperAggregation create instance of WhisperAggregation
func NewWhisperAggregation() *WhisperAggregation {
	return &WhisperAggregation{
		Data: make([]*whisperAggregationItem, 0),
		Default: &whisperAggregationItem{
			name:                 "default",
			pattern:              nil,
			xFilesFactor:         0.5,
			aggregationMethodStr: "average",
			aggregationMethod:    whisper.Average,
		},
	}
}

// ReadWhisperAggregation ...
func ReadWhisperAggregation(file string) (*WhisperAggregation, error) {
	config, err := configparser.Read(file)
	if err != nil {
		return nil, err
	}
	// pp.Println(config)
	sections, err := config.AllSections()
	if err != nil {
		return nil, err
	}

	result := NewWhisperAggregation()

	for _, s := range sections {
		item := &whisperAggregationItem{}
		// this is mildly stupid, but I don't feel like forking
		// configparser just for this
		item.name =
			strings.Trim(strings.SplitN(s.String(), "\n", 2)[0], " []")
		if item.name == "" {
			continue
		}
		item.pattern, err = regexp.Compile(s.ValueOf("pattern"))
		if err != nil {
			logrus.Errorf("[persister] Failed to parse pattern '%s'for [%s]: %s",
				s.ValueOf("pattern"), item.name, err.Error())
			return nil, err
		}

		item.xFilesFactor, err = strconv.ParseFloat(s.ValueOf("xFilesFactor"), 64)
		if err != nil {
			logrus.Errorf("failed to parse xFilesFactor '%s' in %s: %s",
				s.ValueOf("xFilesFactor"), item.name, err.Error())
			continue
		}

		item.aggregationMethodStr = s.ValueOf("aggregationMethod")
		switch item.aggregationMethodStr {
		case "average", "avg":
			item.aggregationMethod = whisper.Average
		case "sum":
			item.aggregationMethod = whisper.Sum
		case "last":
			item.aggregationMethod = whisper.Last
		case "max":
			item.aggregationMethod = whisper.Max
		case "min":
			item.aggregationMethod = whisper.Min
		default:
			logrus.Errorf("unknown aggregation method '%s'",
				s.ValueOf("aggregationMethod"))
			continue
		}

		logrus.Debugf("[persister] adding aggregation [%s] pattern = %s aggregationMethod = %s xFilesFactor = %f",
			item.name, s.ValueOf("pattern"),
			item.aggregationMethodStr, item.xFilesFactor)

		result.Data = append(result.Data, item)
	}

	return result, nil
}

// Match find schema for metric
func (a *WhisperAggregation) match(metric string) *whisperAggregationItem {
	for _, s := range a.Data {
		if s.pattern.MatchString(metric) {
			return s
		}
	}
	return a.Default
}
<commit_msg>fix log msg<commit_after>package persister

/*
Schemas read code from https://github.com/grobian/carbonwriter/
*/

import (
	"regexp"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/alyu/configparser"
	"github.com/lomik/go-whisper"
)

type whisperAggregationItem struct {
	name                 string
	pattern              *regexp.Regexp
	xFilesFactor         float64
	aggregationMethodStr string
	aggregationMethod    whisper.AggregationMethod
}

// WhisperAggregation ...
type WhisperAggregation struct {
	Data    []*whisperAggregationItem
	Default *whisperAggregationItem
}

// NewWhisperAggregation create instance of WhisperAggregation
func NewWhisperAggregation() *WhisperAggregation {
	return &WhisperAggregation{
		Data: make([]*whisperAggregationItem, 0),
		Default: &whisperAggregationItem{
			name:                 "default",
			pattern:              nil,
			xFilesFactor:         0.5,
			aggregationMethodStr: "average",
			aggregationMethod:    whisper.Average,
		},
	}
}

// ReadWhisperAggregation ...
func ReadWhisperAggregation(file string) (*WhisperAggregation, error) {
	config, err := configparser.Read(file)
	if err != nil {
		return nil, err
	}
	// pp.Println(config)
	sections, err := config.AllSections()
	if err != nil {
		return nil, err
	}

	result := NewWhisperAggregation()

	for _, s := range sections {
		item := &whisperAggregationItem{}
		// this is mildly stupid, but I don't feel like forking
		// configparser just for this
		item.name =
			strings.Trim(strings.SplitN(s.String(), "\n", 2)[0], " []")
		if item.name == "" {
			continue
		}
		item.pattern, err = regexp.Compile(s.ValueOf("pattern"))
		if err != nil {
			logrus.Errorf("[persister] Failed to parse pattern '%s'for [%s]: %s",
				s.ValueOf("pattern"), item.name, err.Error())
			return nil, err
		}

		item.xFilesFactor, err = strconv.ParseFloat(s.ValueOf("xFilesFactor"), 64)
		if err != nil {
			logrus.Errorf("failed to parse xFilesFactor '%s' in %s: %s",
				s.ValueOf("xFilesFactor"), item.name, err.Error())
			continue
		}

		item.aggregationMethodStr = s.ValueOf("aggregationMethod")
		switch item.aggregationMethodStr {
		case "average", "avg":
			item.aggregationMethod = whisper.Average
		case "sum":
			item.aggregationMethod = whisper.Sum
		case "last":
			item.aggregationMethod = whisper.Last
		case "max":
			item.aggregationMethod = whisper.Max
		case "min":
			item.aggregationMethod = whisper.Min
		default:
			logrus.Errorf("unknown aggregation method '%s'",
				s.ValueOf("aggregationMethod"))
			continue
		}

		logrus.Debugf("[persister] Adding aggregation [%s] pattern = %s aggregationMethod = %s xFilesFactor = %f",
			item.name, s.ValueOf("pattern"),
			item.aggregationMethodStr, item.xFilesFactor)

		result.Data = append(result.Data, item)
	}

	return result, nil
}

// Match find schema for metric
func (a *WhisperAggregation) match(metric string) *whisperAggregationItem {
	for _, s := range a.Data {
		if s.pattern.MatchString(metric) {
			return s
		}
	}
	return a.Default
}
<|endoftext|>


<commit_before>package sql2kv

import (
	"encoding/json"
	"reflect"
	"testing"
)

var TableSchemaFixture = TableSchema{
	"test",
	"users",
	UserColumnSchemaFixture,
	"id",
}

// UserFixture for tests
var UserColumnSchemaFixture = []ColumnSchema{
	{"test", "users", "id", "int", "NO", "PRI", 1},
	{"test", "users", "name", "text", "YES", "", 2},
	{"test", "users", "age", "int", "YES", "", 3},
	{"test", "users", "hint", "varchar", "YES", "", 4},
	{"test", "users", "alive", "tinyint", "YES", "", 5},
}

// UserJsonFixture for tests
var UserJsonFixture = []map[string]interface{}{
	{
		"name":  "Farhan",
		"age":   int64(32),
		"id":    int64(1),
		"hint":  "hi",
		"alive": true,
		"__pk":  "1",
	},
	{
		"name":  "Coleman",
		"age":   int64(32),
		"id":    int64(2),
		"hint":  "hi",
		"alive": false,
		"__pk":  "2",
	},
	{
		"name":  "Jeff May",
		"age":   int64(27),
		"id":    int64(3),
		"hint":  "hi",
		"alive": true,
		"__pk":  "3",
	},
	{
		"name":  "Mr&MissGophie",
		"age":   int64(1),
		"id":    int64(4),
		"hint":  "hi",
		"alive": false,
		"__pk":  "4",
	},
	{
		"name":  "Dogs",
		"age":   int64(200),
		"id":    int64(5),
		"hint":  "hi",
		"alive": true,
		"__pk":  "5",
	},
	{
		"name":  "GopherThing",
		"age":   int64(20),
		"id":    int64(6),
		"hint":  "hi",
		"alive": false,
		"__pk":  "6",
	},
	{
		"name":  "Linus Torval",
		"age":   int64(100),
		"id":    int64(7),
		"hint":  "hi",
		"alive": true,
		"__pk":  "7",
	},
	{
		"name":  "Rob Pike",
		"age":   int64(100),
		"id":    int64(8),
		"hint":  "hi",
		"alive": false,
		"__pk":  "8",
	},
	{
		"name":  "NinjaMan",
		"age":   int64(23232),
		"id":    int64(9),
		"hint":  "hi",
		"alive": true,
		"__pk":  "9",
	},
	{
		"name":  "Zack",
		"age":   int64(34),
		"id":    int64(10),
		"hint":  "hi",
		"alive": false,
		"__pk":  "10",
	},
}

func TestGetTableSchema(t *testing.T) {

	ts := []struct {
		name string
		in   string
		out  *TableSchema
	}{
		{
			"Testing Basic User Schema",
			"users",
			&TableSchemaFixture,
		},
	}

	for _, ts := range ts {

		actual, err := GetTableSchema(testMySQLDB, "test", ts.in)
		if err != nil {
			t.Errorf("Get Table Schema Failed due to %v", err)
		}

		if !reflect.DeepEqual(ts.out, actual) {
			t.Errorf("\n Expected: %v \n, Acutal: %v \n", ts.out, actual)
			t.FailNow()

		}
	}
}

func TestQueryTableAndWriteKV(t *testing.T) {

	var ts = TableSchema{
		"test",
		"users",
		UserColumnSchemaFixture,
		"id",
	}

	var expectRows = UserJsonFixture

	rows, err := QueryTable(testMySQLDB, ts)
	if err != nil {
		t.Errorf("error from QueryTable %v", err)
	}

	for i, r := range rows {

		if r["__pk"] != expectRows[i]["__pk"] {

			t.Errorf("\n Expected %v \n Acutal %v", expectRows[i], r)
			t.FailNow()
		}

	}

}

func TestWriteKV(t *testing.T) {

	ts := []struct {
		in  map[string]interface{}
		key string
		out map[string]interface{}
	}{
		{
			UserJsonFixture[0],
			"test!users!1",
			map[string]interface{}{
				"id":    float64(1),
				"name":  "Farhan",
				"age":   float64(32),
				"hint":  "hi",
				"alive": true,
				"__pk":  "1",
			},
		},
		{
			UserJsonFixture[1],
			"test!users!2",
			map[string]interface{}{
				"id":    float64(2),
				"name":  "Coleman",
				"age":   float64(32),
				"alive": false,
				"hint":  "hi",

				"__pk": "2",
			},
		},
		{
			UserJsonFixture[2],
			"test!users!3",
			map[string]interface{}{
				"id":    float64(3),
				"name":  "Jeff May",
				"age":   float64(27),
				"hint":  "hi",
				"alive": true,
				"__pk":  "3",
			},
		},
		{
			UserJsonFixture[3],
			"test!users!4",
			map[string]interface{}{
				"id":    float64(4),
				"name":  "Mr&MissGophie",
				"age":   float64(1),
				"hint":  "hi",
				"alive": false,
				"__pk":  "4",
			},
		},
		{
			UserJsonFixture[4],
			"test!users!5",
			map[string]interface{}{
				"id":    float64(5),
				"name":  "Dogs",
				"age":   float64(200),
				"hint":  "hi",
				"alive": true,
				"__pk":  "5",
			},
		},
		{
			UserJsonFixture[5],
			"test!users!6",
			map[string]interface{}{
				"id":    float64(6),
				"name":  "GopherThing",
				"age":   float64(20),
				"hint":  "hi",
				"alive": false,
				"__pk":  "6",
			},
		},
		{
			UserJsonFixture[6],
			"test!users!7",
			map[string]interface{}{
				"id":    float64(7),
				"name":  "Linus Torval",
				"age":   float64(100),
				"hint":  "hi",
				"alive": true,
				"__pk":  "7",
			},
		},
		{
			UserJsonFixture[7],
			"test!users!8",
			map[string]interface{}{
				"id":    float64(8),
				"name":  "Rob Pike",
				"age":   float64(100),
				"hint":  "hi",
				"alive": false,
				"__pk":  "8",
			},
		},
		{
			UserJsonFixture[8],
			"test!users!9",
			map[string]interface{}{
				"id":    float64(9),
				"name":  "NinjaMan",
				"age":   float64(23232),
				"hint":  "hi",
				"alive": true,
				"__pk":  "9",
			},
		},
		{
			UserJsonFixture[9],
			"test!users!10",
			map[string]interface{}{
				"id":    float64(10),
				"name":  "Zack",
				"age":   float64(34),
				"hint":  "hi",
				"alive": false,
				"__pk":  "10",
			},
		},
	}

	for _, c := range ts {
		err := WriteKV(testLevelDB, TableSchemaFixture, c.in, "!")
		if err != nil {
			t.Errorf("error from WriteKV: %v", err)
		}

		found, err := testLevelDB.Get([]byte(c.key), nil)
		if err != nil {
			t.Errorf("could not find key: %v", err)
		}

		var actual map[string]interface{}
		if err := json.Unmarshal(found, &actual); err != nil {
			t.Error(err)
		}
		if !reflect.DeepEqual(c.out, actual) {

			t.Errorf("\n Expected %v \n Acutal %v", c.out, actual)
			t.FailNow()
		}

	}

}
<commit_msg>Adjust names and add docstrings.<commit_after>package sql2kv

import (
	"encoding/json"
	"reflect"
	"testing"
)

// UsersTableSchemaFixture models our "test.users" table.
var UsersTableSchemaFixture = TableSchema{
	"test",
	"users",
	UsersColumnSchemaFixture,
	"id",
}

// UsersColumnSchemaFixture models a subset of INFORMATION_SCHEMA.COLUMNS for
// our "test.users" table.
var UsersColumnSchemaFixture = []ColumnSchema{
	{"test", "users", "id", "int", "NO", "PRI", 1},
	{"test", "users", "name", "text", "YES", "", 2},
	{"test", "users", "age", "int", "YES", "", 3},
	{"test", "users", "hint", "varchar", "YES", "", 4},
	{"test", "users", "alive", "tinyint", "YES", "", 5},
}

// UserJSONSchema models the JSON serializable types for our "test.users" table.
// We expect these results to be written and read as []byte to and from a local
// kv store.
var UserJSONSchema = []map[string]interface{}{
	{
		"name":  "Farhan",
		"age":   int64(32),
		"id":    int64(1),
		"hint":  "hi",
		"alive": true,
		"__pk":  "1",
	},
	{
		"name":  "Coleman",
		"age":   int64(32),
		"id":    int64(2),
		"hint":  "hi",
		"alive": false,
		"__pk":  "2",
	},
	{
		"name":  "Jeff May",
		"age":   int64(27),
		"id":    int64(3),
		"hint":  "hi",
		"alive": true,
		"__pk":  "3",
	},
	{
		"name":  "Mr&MissGophie",
		"age":   int64(1),
		"id":    int64(4),
		"hint":  "hi",
		"alive": false,
		"__pk":  "4",
	},
	{
		"name":  "Dogs",
		"age":   int64(200),
		"id":    int64(5),
		"hint":  "hi",
		"alive": true,
		"__pk":  "5",
	},
	{
		"name":  "GopherThing",
		"age":   int64(20),
		"id":    int64(6),
		"hint":  "hi",
		"alive": false,
		"__pk":  "6",
	},
	{
		"name":  "Linus Torval",
		"age":   int64(100),
		"id":    int64(7),
		"hint":  "hi",
		"alive": true,
		"__pk":  "7",
	},
	{
		"name":  "Rob Pike",
		"age":   int64(100),
		"id":    int64(8),
		"hint":  "hi",
		"alive": false,
		"__pk":  "8",
	},
	{
		"name":  "NinjaMan",
		"age":   int64(23232),
		"id":    int64(9),
		"hint":  "hi",
		"alive": true,
		"__pk":  "9",
	},
	{
		"name":  "Zack",
		"age":   int64(34),
		"id":    int64(10),
		"hint":  "hi",
		"alive": false,
		"__pk":  "10",
	},
}

func TestGetTableSchema(t *testing.T) {

	ts := []struct {
		name string
		in   string
		out  *TableSchema
	}{
		{
			"Testing Basic User Schema",
			"users",
			&UsersTableSchemaFixture,
		},
	}

	for _, ts := range ts {

		actual, err := GetTableSchema(testMySQLDB, "test", ts.in)
		if err != nil {
			t.Errorf("Get Table Schema Failed due to %v", err)
		}

		if !reflect.DeepEqual(ts.out, actual) {
			t.Errorf("\n Expected: %v \n, Acutal: %v \n", ts.out, actual)
			t.FailNow()

		}
	}
}

func TestQueryTableAndWriteKV(t *testing.T) {

	var ts = TableSchema{
		"test",
		"users",
		UsersColumnSchemaFixture,
		"id",
	}

	var expectRows = UserJSONSchema

	rows, err := QueryTable(testMySQLDB, ts)
	if err != nil {
		t.Errorf("error from QueryTable %v", err)
	}

	for i, r := range rows {

		if r["__pk"] != expectRows[i]["__pk"] {

			t.Errorf("\n Expected %v \n Acutal %v", expectRows[i], r)
			t.FailNow()
		}

	}

}

func TestWriteKV(t *testing.T) {

	ts := []struct {
		in  map[string]interface{}
		key string
		out map[string]interface{}
	}{
		{
			UserJSONSchema[0],
			"test!users!1",
			map[string]interface{}{
				"id":    float64(1),
				"name":  "Farhan",
				"age":   float64(32),
				"hint":  "hi",
				"alive": true,
				"__pk":  "1",
			},
		},
		{
			UserJSONSchema[1],
			"test!users!2",
			map[string]interface{}{
				"id":    float64(2),
				"name":  "Coleman",
				"age":   float64(32),
				"alive": false,
				"hint":  "hi",

				"__pk": "2",
			},
		},
		{
			UserJSONSchema[2],
			"test!users!3",
			map[string]interface{}{
				"id":    float64(3),
				"name":  "Jeff May",
				"age":   float64(27),
				"hint":  "hi",
				"alive": true,
				"__pk":  "3",
			},
		},
		{
			UserJSONSchema[3],
			"test!users!4",
			map[string]interface{}{
				"id":    float64(4),
				"name":  "Mr&MissGophie",
				"age":   float64(1),
				"hint":  "hi",
				"alive": false,
				"__pk":  "4",
			},
		},
		{
			UserJSONSchema[4],
			"test!users!5",
			map[string]interface{}{
				"id":    float64(5),
				"name":  "Dogs",
				"age":   float64(200),
				"hint":  "hi",
				"alive": true,
				"__pk":  "5",
			},
		},
		{
			UserJSONSchema[5],
			"test!users!6",
			map[string]interface{}{
				"id":    float64(6),
				"name":  "GopherThing",
				"age":   float64(20),
				"hint":  "hi",
				"alive": false,
				"__pk":  "6",
			},
		},
		{
			UserJSONSchema[6],
			"test!users!7",
			map[string]interface{}{
				"id":    float64(7),
				"name":  "Linus Torval",
				"age":   float64(100),
				"hint":  "hi",
				"alive": true,
				"__pk":  "7",
			},
		},
		{
			UserJSONSchema[7],
			"test!users!8",
			map[string]interface{}{
				"id":    float64(8),
				"name":  "Rob Pike",
				"age":   float64(100),
				"hint":  "hi",
				"alive": false,
				"__pk":  "8",
			},
		},
		{
			UserJSONSchema[8],
			"test!users!9",
			map[string]interface{}{
				"id":    float64(9),
				"name":  "NinjaMan",
				"age":   float64(23232),
				"hint":  "hi",
				"alive": true,
				"__pk":  "9",
			},
		},
		{
			UserJSONSchema[9],
			"test!users!10",
			map[string]interface{}{
				"id":    float64(10),
				"name":  "Zack",
				"age":   float64(34),
				"hint":  "hi",
				"alive": false,
				"__pk":  "10",
			},
		},
	}

	for _, c := range ts {
		err := WriteKV(testLevelDB, UsersTableSchemaFixture, c.in, "!")
		if err != nil {
			t.Errorf("error from WriteKV: %v", err)
		}

		found, err := testLevelDB.Get([]byte(c.key), nil)
		if err != nil {
			t.Errorf("could not find key: %v", err)
		}

		var actual map[string]interface{}
		if err := json.Unmarshal(found, &actual); err != nil {
			t.Error(err)
		}
		if !reflect.DeepEqual(c.out, actual) {

			t.Errorf("\n Expected %v \n Acutal %v", c.out, actual)
			t.FailNow()
		}

	}

}
<|endoftext|>


<commit_before>/*
Copyright 2015 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 to keep track of API Versions that should be registered in api.Scheme.
package registered

import (
	"os"
	"strings"

	"github.com/golang/glog"
	apiutil "k8s.io/kubernetes/pkg/api/util"
)

// List of registered API versions.
// The list is in the order of most preferred to the least.
var RegisteredVersions []string

func init() {
	// TODO: caesarxuchao: rename this variable to validGroupVersions
	validAPIVersions := map[string]bool{
		"v1":                 true,
		"extensions/v1beta1": true,
	}

	// The default list of supported api versions, in order of most preferred to the least.
	defaultSupportedVersions := "v1,extensions/v1beta1"
	// Env var KUBE_API_VERSIONS is a comma separated list of API versions that should be registered in the scheme.
	// The versions should be in the order of most preferred to the least.
	supportedVersions := os.Getenv("KUBE_API_VERSIONS")
	if supportedVersions == "" {
		supportedVersions = defaultSupportedVersions
	}
	versions := strings.Split(supportedVersions, ",")
	for _, version := range versions {
		// Verify that the version is valid.
		valid, ok := validAPIVersions[version]
		if !ok || !valid {
			// Not a valid API version.
			glog.Fatalf("Invalid api version: %s in KUBE_API_VERSIONS: %s. List of valid API versions: %v",
				version, os.Getenv("KUBE_API_VERSIONS"), validAPIVersions)
		}
		RegisteredVersions = append(RegisteredVersions, version)
	}
}

// Returns true if the given api version is one of the registered api versions.
func IsRegisteredAPIVersion(version string) bool {
	for _, apiVersion := range RegisteredVersions {
		if apiVersion == version {
			return true
		}
	}
	return false
}

// GroupVersionsForGroup returns the registered versions of a group in the form
// of "group/version".
func GroupVersionsForGroup(group string) []string {
	ret := []string{}
	for _, v := range RegisteredVersions {
		if apiutil.GetGroup(v) == group {
			ret = append(ret, v)
		}
	}
	return ret
}
<commit_msg>Implement kubectl autoscale<commit_after>/*
Copyright 2015 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 to keep track of API Versions that should be registered in api.Scheme.
package registered

import (
	"os"
	"strings"

	"github.com/golang/glog"
	apiutil "k8s.io/kubernetes/pkg/api/util"
)

// List of registered API versions.
// The list is in the order of most preferred to the least.
var RegisteredVersions []string

func init() {
	// TODO: caesarxuchao: rename this variable to validGroupVersions
	validAPIVersions := map[string]bool{
		"v1":                 true,
		"extensions/v1beta1": true,
	}

	// The default list of supported api versions, in order of most preferred to the least.
	defaultSupportedVersions := "v1,extensions/v1beta1"
	// Env var KUBE_API_VERSIONS is a comma separated list of API versions that should be registered in the scheme.
	// The versions should be in the order of most preferred to the least.
	supportedVersions := os.Getenv("KUBE_API_VERSIONS")
	if supportedVersions == "" {
		supportedVersions = defaultSupportedVersions
	}
	versions := strings.Split(supportedVersions, ",")
	for _, version := range versions {
		// Verify that the version is valid.
		valid, ok := validAPIVersions[version]
		if !ok || !valid {
			// Not a valid API version.
			glog.Fatalf("invalid api version: %s in KUBE_API_VERSIONS: %s. List of valid API versions: %v",
				version, os.Getenv("KUBE_API_VERSIONS"), validAPIVersions)
		}
		RegisteredVersions = append(RegisteredVersions, version)
	}
}

// Returns true if the given api version is one of the registered api versions.
func IsRegisteredAPIVersion(version string) bool {
	for _, apiVersion := range RegisteredVersions {
		if apiVersion == version {
			return true
		}
	}
	return false
}

// GroupVersionsForGroup returns the registered versions of a group in the form
// of "group/version".
func GroupVersionsForGroup(group string) []string {
	ret := []string{}
	for _, v := range RegisteredVersions {
		if apiutil.GetGroup(v) == group {
			ret = append(ret, v)
		}
	}
	return ret
}
<|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 util

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

// IsDefaultStorageClassAnnotation represents a StorageClass annotation that
// marks a class as the default StorageClass
//TODO: Update IsDefaultStorageClassannotation and remove Beta when no longer used
const IsDefaultStorageClassAnnotation = "storageclass.beta.kubernetes.io/is-default-class"
const BetaIsDefaultStorageClassAnnotation = "storageclass.beta.kubernetes.io/is-default-class"

// IsDefaultAnnotationText returns a pretty Yes/No String if
// the annotation is set
// TODO: remove Beta when no longer needed
func IsDefaultAnnotationText(obj metav1.ObjectMeta) string {
	if obj.Annotations[IsDefaultStorageClassAnnotation] == "true" {
		return "Yes"
	}
	if obj.Annotations[BetaIsDefaultStorageClassAnnotation] == "true" {
		return "Yes"
	}

	return "No"
}

// IsDefaultAnnotation returns a boolean if
// the annotation is set
// TODO: remove Beta when no longer needed
func IsDefaultAnnotation(obj metav1.ObjectMeta) bool {
	if obj.Annotations[IsDefaultStorageClassAnnotation] == "true" {
		return true
	}
	if obj.Annotations[BetaIsDefaultStorageClassAnnotation] == "true" {
		return true
	}

	return false
}
<commit_msg>Remove 'beta' from default storage class annotation (storage/util)<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 util

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

// IsDefaultStorageClassAnnotation represents a StorageClass annotation that
// marks a class as the default StorageClass
//TODO: remove Beta when no longer used
const IsDefaultStorageClassAnnotation = "storageclass.kubernetes.io/is-default-class"
const BetaIsDefaultStorageClassAnnotation = "storageclass.beta.kubernetes.io/is-default-class"

// IsDefaultAnnotationText returns a pretty Yes/No String if
// the annotation is set
// TODO: remove Beta when no longer needed
func IsDefaultAnnotationText(obj metav1.ObjectMeta) string {
	if obj.Annotations[IsDefaultStorageClassAnnotation] == "true" {
		return "Yes"
	}
	if obj.Annotations[BetaIsDefaultStorageClassAnnotation] == "true" {
		return "Yes"
	}

	return "No"
}

// IsDefaultAnnotation returns a boolean if
// the annotation is set
// TODO: remove Beta when no longer needed
func IsDefaultAnnotation(obj metav1.ObjectMeta) bool {
	if obj.Annotations[IsDefaultStorageClassAnnotation] == "true" {
		return true
	}
	if obj.Annotations[BetaIsDefaultStorageClassAnnotation] == "true" {
		return true
	}

	return false
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Google Inc. 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 container

import (
	"fmt"
	"strings"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
)

// Runtime interface defines the interfaces that should be implemented
// by a container runtime.
type Runtime interface {
	// Version returns a map of version information of the container runtime.
	Version() (map[string]string, error)
	// GetPods returns a list containers group by pods. The boolean parameter
	// specifies whether the runtime returns all containers including those already
	// exited and dead containers (used for garbage collection).
	GetPods(all bool) ([]*Pod, error)
	// RunPod starts all the containers of a pod within a namespace.
	RunPod(*api.Pod, map[string]volume.VolumePlugin) error
	// KillPod kills all the containers of a pod.
	KillPod(*api.Pod) error
	// RunContainerInPod starts a container within the same namespace of a pod.
	RunContainerInPod(api.Container, *api.Pod, map[string]volume.VolumePlugin) error
	// KillContainerInPod kills a container in the pod.
	KillContainerInPod(api.Container, *api.Pod) error
	// GetPodStatus retrieves the status of the pod, including the information of
	// all containers in the pod.
	GetPodStatus(*Pod) (api.PodStatus, error)
	// GetContainers returns all containers on the node, including those are
	// not managed by kubelet. If 'all' is false, then only running containers
	// are returned.
	GetContainers(all bool) ([]*Container, error)
	// TODO(yifan): Pull/Remove images
}

// Pod is a group of containers, with the status of the pod.
type Pod struct {
	// The ID of the pod, which can be used to retrieve a particular pod
	// from the pod list returned by GetPods().
	ID types.UID
	// The name and namespace of the pod, which is readable by human.
	Name      string
	Namespace string
	// List of containers that belongs to this pod. It may contain only
	// running containers, or mixed with dead ones (when GetPods(true)).
	Containers []*Container
	// The status of the pod.
	// TODO(yifan): Inspect and get the statuses for all pods can be expensive,
	// maybe we want to get one pod's status at a time (e.g. GetPodStatus()
	// for the particular pod after we GetPods()).
	Status api.PodStatus
}

// Container provides the runtime information for a container, such as ID, hash,
// status of the container.
type Container struct {
	// The ID of the container, used by the container runtime to identify
	// a container.
	ID types.UID
	// The name of the container, which should be the same as specified by
	// api.Container.
	Name string
	// The image name of the container.
	Image string
	// Hash of the container, used for comparison. Optional for containers
	// not managed by kubelet.
	Hash uint64
	// The timestamp of the creation time of the container.
	// TODO(yifan): Consider to move it to api.ContainerStatus.
	Created int64
}

type Pods []*Pod

// FindPodByID returns a pod in the pod list by UID. It will return an empty pod
// if not found.
// TODO(yifan): Use a map?
func (p Pods) FindPodByID(podUID types.UID) Pod {
	for i := range p {
		if p[i].ID == podUID {
			return *p[i]
		}
	}
	return Pod{}
}

// FindContainerByName returns a container in the pod with the given name.
// When there are multiple containers with the same name, the first match will
// be returned.
func (p *Pod) FindContainerByName(containerName string) *Container {
	for _, c := range p.Containers {
		if c.Name == containerName {
			return c
		}
	}
	return nil
}

// GetPodFullName returns a name that uniquely identifies a pod.
func GetPodFullName(pod *api.Pod) string {
	// Use underscore as the delimiter because it is not allowed in pod name
	// (DNS subdomain format), while allowed in the container name format.
	return fmt.Sprintf("%s_%s", pod.Name, pod.Namespace)
}

// Build the pod full name from pod name and namespace.
func BuildPodFullName(name, namespace string) string {
	return name + "_" + namespace
}

// Parse the pod full name.
func ParsePodFullName(podFullName string) (string, string, error) {
	parts := strings.Split(podFullName, "_")
	if len(parts) != 2 {
		return "", "", fmt.Errorf("failed to parse the pod full name %q", podFullName)
	}
	return parts[0], parts[1], nil
}
<commit_msg>kubelet.container: Fix volume map type.<commit_after>/*
Copyright 2015 Google Inc. 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 container

import (
	"fmt"
	"strings"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
)

// Runtime interface defines the interfaces that should be implemented
// by a container runtime.
type Runtime interface {
	// Version returns a map of version information of the container runtime.
	Version() (map[string]string, error)
	// GetPods returns a list containers group by pods. The boolean parameter
	// specifies whether the runtime returns all containers including those already
	// exited and dead containers (used for garbage collection).
	GetPods(all bool) ([]*Pod, error)
	// RunPod starts all the containers of a pod within a namespace.
	RunPod(*api.Pod, map[string]volume.Volume) error
	// KillPod kills all the containers of a pod.
	KillPod(*api.Pod) error
	// RunContainerInPod starts a container within the same namespace of a pod.
	RunContainerInPod(api.Container, *api.Pod, map[string]volume.Volume) error
	// KillContainerInPod kills a container in the pod.
	KillContainerInPod(api.Container, *api.Pod) error
	// GetPodStatus retrieves the status of the pod, including the information of
	// all containers in the pod.
	GetPodStatus(*Pod) (api.PodStatus, error)
	// GetContainers returns all containers on the node, including those are
	// not managed by kubelet. If 'all' is false, then only running containers
	// are returned.
	GetContainers(all bool) ([]*Container, error)
	// TODO(yifan): Pull/Remove images
}

// Pod is a group of containers, with the status of the pod.
type Pod struct {
	// The ID of the pod, which can be used to retrieve a particular pod
	// from the pod list returned by GetPods().
	ID types.UID
	// The name and namespace of the pod, which is readable by human.
	Name      string
	Namespace string
	// List of containers that belongs to this pod. It may contain only
	// running containers, or mixed with dead ones (when GetPods(true)).
	Containers []*Container
	// The status of the pod.
	// TODO(yifan): Inspect and get the statuses for all pods can be expensive,
	// maybe we want to get one pod's status at a time (e.g. GetPodStatus()
	// for the particular pod after we GetPods()).
	Status api.PodStatus
}

// Container provides the runtime information for a container, such as ID, hash,
// status of the container.
type Container struct {
	// The ID of the container, used by the container runtime to identify
	// a container.
	ID types.UID
	// The name of the container, which should be the same as specified by
	// api.Container.
	Name string
	// The image name of the container.
	Image string
	// Hash of the container, used for comparison. Optional for containers
	// not managed by kubelet.
	Hash uint64
	// The timestamp of the creation time of the container.
	// TODO(yifan): Consider to move it to api.ContainerStatus.
	Created int64
}

type Pods []*Pod

// FindPodByID returns a pod in the pod list by UID. It will return an empty pod
// if not found.
// TODO(yifan): Use a map?
func (p Pods) FindPodByID(podUID types.UID) Pod {
	for i := range p {
		if p[i].ID == podUID {
			return *p[i]
		}
	}
	return Pod{}
}

// FindContainerByName returns a container in the pod with the given name.
// When there are multiple containers with the same name, the first match will
// be returned.
func (p *Pod) FindContainerByName(containerName string) *Container {
	for _, c := range p.Containers {
		if c.Name == containerName {
			return c
		}
	}
	return nil
}

// GetPodFullName returns a name that uniquely identifies a pod.
func GetPodFullName(pod *api.Pod) string {
	// Use underscore as the delimiter because it is not allowed in pod name
	// (DNS subdomain format), while allowed in the container name format.
	return fmt.Sprintf("%s_%s", pod.Name, pod.Namespace)
}

// Build the pod full name from pod name and namespace.
func BuildPodFullName(name, namespace string) string {
	return name + "_" + namespace
}

// Parse the pod full name.
func ParsePodFullName(podFullName string) (string, string, error) {
	parts := strings.Split(podFullName, "_")
	if len(parts) != 2 {
		return "", "", fmt.Errorf("failed to parse the pod full name %q", podFullName)
	}
	return parts[0], parts[1], nil
}
<|endoftext|>


<commit_before>// Copyright 2018 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 vmbased

import (
	"fmt"
	"strings"

	pilotclient "openpitrix.io/openpitrix/pkg/client/pilot"
	"openpitrix.io/openpitrix/pkg/constants"
	"openpitrix.io/openpitrix/pkg/logger"
	"openpitrix.io/openpitrix/pkg/models"
	"openpitrix.io/openpitrix/pkg/pb/metadata/types"
	metadatatypes "openpitrix.io/openpitrix/pkg/pb/metadata/types"
	types "openpitrix.io/openpitrix/pkg/pb/metadata/types"
	"openpitrix.io/openpitrix/pkg/pi"
	"openpitrix.io/openpitrix/pkg/util/jsonutil"
	"openpitrix.io/openpitrix/pkg/util/retryutil"
	"openpitrix.io/openpitrix/pkg/util/sshutil"
)

type Frontgate struct {
	*Frame
}

/*
cat /opt/openpitrix/conf/drone.conf
IMAGE="mysql:5.7"
MOUNT_POINT="/data"
FILE_NAME="frontgate.conf"
FILE_CONF={\\"id\\":\\"cln-abcdefgh\\",\\"listen_port\\":9111,\\"pilot_host\\":192.168.0.1,\\"pilot_port\\":9110}
*/
func (f *Frontgate) getUserDataValue(nodeId string) string {
	var result string
	clusterNode := f.ClusterWrapper.ClusterNodesWithKeyPairs[nodeId]
	role := clusterNode.Role
	if strings.HasSuffix(role, constants.ReplicaRoleSuffix) {
		role = string([]byte(role)[:len(role)-len(constants.ReplicaRoleSuffix)])
	}
	clusterRole, _ := f.ClusterWrapper.ClusterRoles[role]
	clusterCommon, _ := f.ClusterWrapper.ClusterCommons[role]
	mountPoint := clusterRole.MountPoint
	// Empty string can not be a parameter
	if len(mountPoint) == 0 {
		mountPoint = "#"
	}
	imageId := clusterCommon.ImageId

	frontgateConf := make(map[string]interface{})
	frontgateConf["id"] = f.ClusterWrapper.Cluster.ClusterId
	frontgateConf["node_id"] = nodeId
	frontgateConf["listen_port"] = constants.FrontgateServicePort
	frontgateConf["pilot_host"] = pi.Global().GlobalConfig().Pilot.Ip
	if pi.Global().GlobalConfig().Pilot.Port > 0 {
		frontgateConf["pilot_port"] = pi.Global().GlobalConfig().Pilot.Port
	} else {
		frontgateConf["pilot_port"] = constants.PilotServicePort
	}
	frontgateConfStr := strings.Replace(jsonutil.ToString(frontgateConf), "\"", "\\\\\"", -1)

	result += fmt.Sprintf("IMAGE=\"%s\"\n", imageId)
	result += fmt.Sprintf("MOUNT_POINT=\"%s\"\n", mountPoint)
	result += fmt.Sprintf("FILE_NAME=\"%s\"\n", FrontgateConfFile)
	result += fmt.Sprintf("FILE_CONF=%s\n", frontgateConfStr)

	return result
}

func (f *Frontgate) getCertificateExec() string {
	var pilotClientTLSConfig *types.PilotClientTLSConfig

	err := retryutil.Retry(3, constants.RetryInterval, func() error {
		pilotClient, err := pilotclient.NewClient()
		if err != nil {
			return err
		}
		pilotClientTLSConfig, err = pilotClient.GetPilotClientTLSConfig(f.Ctx, &metadatatypes.Empty{})
		if err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		logger.Critical(f.Ctx, "Get pilot client tls config failed, %+v", err)
		return ""
	}

	exec := fmt.Sprintf(`
echo '%s' > /opt/openpitrix/conf/openpitrix-ca.crt
echo '%s' > /opt/openpitrix/conf/pilot-client.crt
echo '%s' > /opt/openpitrix/conf/pilot-client.key
`, pilotClientTLSConfig.CaCrtData, pilotClientTLSConfig.ClientCrtData, pilotClientTLSConfig.ClientKeyData)

	return exec
}

func (f *Frontgate) pingFrontgateLayer(failureAllowed bool) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)

	directive := jsonutil.ToString(&models.Meta{
		ClusterId: f.ClusterWrapper.Cluster.ClusterId,
	})

	task := &models.Task{
		JobId:          f.Job.JobId,
		Owner:          f.Job.Owner,
		TaskAction:     ActionPingFrontgate,
		Target:         constants.TargetPilot,
		NodeId:         f.ClusterWrapper.Cluster.ClusterId,
		Directive:      directive,
		FailureAllowed: failureAllowed,
	}
	taskLayer.Tasks = append(taskLayer.Tasks, task)
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) setFrontgateConfigLayer(nodeIds []string, failureAllowed bool) *models.TaskLayer {
	var tasks []*models.Task
	directive := jsonutil.ToString(&models.Meta{
		ClusterId: f.ClusterWrapper.Cluster.ClusterId,
	})

	for _, nodeId := range nodeIds {
		// get frontgate config when pre task
		task := &models.Task{
			JobId:          f.Job.JobId,
			Owner:          f.Job.Owner,
			TaskAction:     ActionSetFrontgateConfig,
			Target:         constants.TargetPilot,
			NodeId:         nodeId,
			Directive:      directive,
			FailureAllowed: failureAllowed,
		}
		tasks = append(tasks, task)
	}
	return &models.TaskLayer{
		Tasks: tasks,
	}
}

func (f *Frontgate) pingMetadataBackendLayer(failureAllowed bool) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)

	directive := jsonutil.ToString(&models.Meta{
		ClusterId: f.ClusterWrapper.Cluster.ClusterId,
	})

	task := &models.Task{
		JobId:          f.Job.JobId,
		Owner:          f.Job.Owner,
		TaskAction:     PingMetadataBackend,
		Target:         constants.TargetPilot,
		NodeId:         f.ClusterWrapper.Cluster.ClusterId,
		Directive:      directive,
		FailureAllowed: failureAllowed,
	}
	taskLayer.Tasks = append(taskLayer.Tasks, task)
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) removeContainerLayer(nodeIds []string, failureAllowed bool) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)

	for nodeId, clusterNode := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		ip := clusterNode.PrivateIp
		cmd := fmt.Sprintf("%s \"docker rm -f default\"", HostCmdPrefix)
		request := &pbtypes.RunCommandOnFrontgateRequest{
			Endpoint: &pbtypes.FrontgateEndpoint{
				FrontgateId:     f.ClusterWrapper.Cluster.ClusterId,
				FrontgateNodeId: nodeId,
				NodeIp:          ip,
				NodePort:        constants.FrontgateServicePort,
			},
			Command:        cmd,
			TimeoutSeconds: TimeoutRemoveContainer,
		}
		directive := jsonutil.ToString(request)
		formatVolumeTask := &models.Task{
			JobId:          f.Job.JobId,
			Owner:          f.Job.Owner,
			TaskAction:     ActionRemoveContainerOnFrontgate,
			Target:         constants.TargetPilot,
			NodeId:         nodeId,
			Directive:      directive,
			FailureAllowed: failureAllowed,
		}
		taskLayer.Tasks = append(taskLayer.Tasks, formatVolumeTask)
	}
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) attachKeyPairLayer(nodeKeyPairDetail *models.NodeKeyPairDetail) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)
	clusterNode := nodeKeyPairDetail.ClusterNode
	request := &pbtypes.RunCommandOnFrontgateRequest{
		Endpoint: &pbtypes.FrontgateEndpoint{
			FrontgateId:     f.ClusterWrapper.Cluster.ClusterId,
			FrontgateNodeId: clusterNode.NodeId,
			NodeIp:          clusterNode.PrivateIp,
			NodePort:        constants.FrontgateServicePort,
		},
		Command:        fmt.Sprintf("%s \"%s\"", HostCmdPrefix, sshutil.DoAttachCmd(nodeKeyPairDetail.KeyPair.PubKey)),
		TimeoutSeconds: TimeoutKeyPair,
	}
	directive := jsonutil.ToString(request)
	attachKeyPairTask := &models.Task{
		JobId:          f.Job.JobId,
		Owner:          f.Job.Owner,
		TaskAction:     ActionRunCommandOnFrontgateNode,
		Target:         constants.TargetPilot,
		NodeId:         clusterNode.NodeId,
		Directive:      directive,
		FailureAllowed: false,
	}
	taskLayer.Tasks = append(taskLayer.Tasks, attachKeyPairTask)
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) detachKeyPairLayer(nodeKeyPairDetail *models.NodeKeyPairDetail) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)
	clusterNode := nodeKeyPairDetail.ClusterNode
	request := &pbtypes.RunCommandOnFrontgateRequest{
		Endpoint: &pbtypes.FrontgateEndpoint{
			FrontgateId:     f.ClusterWrapper.Cluster.ClusterId,
			FrontgateNodeId: clusterNode.NodeId,
			NodeIp:          clusterNode.PrivateIp,
			NodePort:        constants.FrontgateServicePort,
		},
		Command:        fmt.Sprintf("%s \"%s\"", HostCmdPrefix, sshutil.DoDetachCmd(nodeKeyPairDetail.KeyPair.PubKey)),
		TimeoutSeconds: TimeoutKeyPair,
	}
	directive := jsonutil.ToString(request)
	attachKeyPairTask := &models.Task{
		JobId:          f.Job.JobId,
		Owner:          f.Job.Owner,
		TaskAction:     ActionRunCommandOnFrontgateNode,
		Target:         constants.TargetPilot,
		NodeId:         clusterNode.NodeId,
		Directive:      directive,
		FailureAllowed: false,
	}
	taskLayer.Tasks = append(taskLayer.Tasks, attachKeyPairTask)
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) CreateClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	headTaskLayer.
		Append(f.createVolumesLayer(nodeIds, false)).        // create volume
		Append(f.runInstancesLayer(nodeIds, false)).         // run instance and attach volume to instance
		Append(f.pingFrontgateLayer(false)).                 // ping frontgate
		Append(f.formatAndMountVolumeLayer(nodeIds, false)). // format and mount volume to instance
		Append(f.removeContainerLayer(nodeIds, false)).      // remove default container
		Append(f.pingFrontgateLayer(false)).                 // ping frontgate
		Append(f.setFrontgateConfigLayer(nodeIds, false)).   // set frontgate config
		Append(f.pingMetadataBackendLayer(false))            // ping metadata backend

	return headTaskLayer.Child
}

func (f *Frontgate) DeleteClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	if f.ClusterWrapper.Cluster.Status == constants.StatusActive {
		headTaskLayer.
			Append(f.umountVolumeLayer(nodeIds, true)).  // umount volume from instance
			Append(f.stopInstancesLayer(nodeIds, true)). // stop instance
			Append(f.detachVolumesLayer(nodeIds, false)) // detach volume from instance
	}

	headTaskLayer.
		Append(f.deleteInstancesLayer(nodeIds, false)). // delete instance
		Append(f.deleteVolumesLayer(nodeIds, false))    // delete volume
	return headTaskLayer.Child
}

func (f *Frontgate) StartClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	headTaskLayer.
		Append(f.attachVolumesLayer(nodeIds, false)).      // attach volume to instance, will auto mount
		Append(f.startInstancesLayer(nodeIds, false)).     // run instance and attach volume to instance
		Append(f.pingFrontgateLayer(false)).               // ping frontgate
		Append(f.setFrontgateConfigLayer(nodeIds, false)). // set frontgate config
		Append(f.pingMetadataBackendLayer(false))          // ping metadata backend

	return headTaskLayer.Child
}

func (f *Frontgate) StopClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	headTaskLayer.
		Append(f.umountVolumeLayer(nodeIds, true)).   // umount volume from instance
		Append(f.detachVolumesLayer(nodeIds, false)). // detach volume from instance
		Append(f.stopInstancesLayer(nodeIds, false))  // delete instance

	return headTaskLayer.Child
}

func (f *Frontgate) AttachKeyPairsLayer(nodeKeyPairDetails models.NodeKeyPairDetails) *models.TaskLayer {
	headTaskLayer := new(models.TaskLayer)

	for _, nodeKeyPairDetail := range nodeKeyPairDetails {
		headTaskLayer.Append(f.attachKeyPairLayer(&nodeKeyPairDetail))
	}

	return headTaskLayer.Child
}

func (f *Frontgate) DetachKeyPairsLayer(nodeKeyPairDetails models.NodeKeyPairDetails) *models.TaskLayer {
	headTaskLayer := new(models.TaskLayer)

	for _, nodeKeyPairDetail := range nodeKeyPairDetails {
		headTaskLayer.Append(f.detachKeyPairLayer(&nodeKeyPairDetail))
	}

	return headTaskLayer.Child
}
<commit_msg>Fix stop aws frontgate failed: stop instance then detach volume<commit_after>// Copyright 2018 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 vmbased

import (
	"fmt"
	"strings"

	pilotclient "openpitrix.io/openpitrix/pkg/client/pilot"
	"openpitrix.io/openpitrix/pkg/constants"
	"openpitrix.io/openpitrix/pkg/logger"
	"openpitrix.io/openpitrix/pkg/models"
	"openpitrix.io/openpitrix/pkg/pb/metadata/types"
	metadatatypes "openpitrix.io/openpitrix/pkg/pb/metadata/types"
	types "openpitrix.io/openpitrix/pkg/pb/metadata/types"
	"openpitrix.io/openpitrix/pkg/pi"
	"openpitrix.io/openpitrix/pkg/util/jsonutil"
	"openpitrix.io/openpitrix/pkg/util/retryutil"
	"openpitrix.io/openpitrix/pkg/util/sshutil"
)

type Frontgate struct {
	*Frame
}

/*
cat /opt/openpitrix/conf/drone.conf
IMAGE="mysql:5.7"
MOUNT_POINT="/data"
FILE_NAME="frontgate.conf"
FILE_CONF={\\"id\\":\\"cln-abcdefgh\\",\\"listen_port\\":9111,\\"pilot_host\\":192.168.0.1,\\"pilot_port\\":9110}
*/
func (f *Frontgate) getUserDataValue(nodeId string) string {
	var result string
	clusterNode := f.ClusterWrapper.ClusterNodesWithKeyPairs[nodeId]
	role := clusterNode.Role
	if strings.HasSuffix(role, constants.ReplicaRoleSuffix) {
		role = string([]byte(role)[:len(role)-len(constants.ReplicaRoleSuffix)])
	}
	clusterRole, _ := f.ClusterWrapper.ClusterRoles[role]
	clusterCommon, _ := f.ClusterWrapper.ClusterCommons[role]
	mountPoint := clusterRole.MountPoint
	// Empty string can not be a parameter
	if len(mountPoint) == 0 {
		mountPoint = "#"
	}
	imageId := clusterCommon.ImageId

	frontgateConf := make(map[string]interface{})
	frontgateConf["id"] = f.ClusterWrapper.Cluster.ClusterId
	frontgateConf["node_id"] = nodeId
	frontgateConf["listen_port"] = constants.FrontgateServicePort
	frontgateConf["pilot_host"] = pi.Global().GlobalConfig().Pilot.Ip
	if pi.Global().GlobalConfig().Pilot.Port > 0 {
		frontgateConf["pilot_port"] = pi.Global().GlobalConfig().Pilot.Port
	} else {
		frontgateConf["pilot_port"] = constants.PilotServicePort
	}
	frontgateConfStr := strings.Replace(jsonutil.ToString(frontgateConf), "\"", "\\\\\"", -1)

	result += fmt.Sprintf("IMAGE=\"%s\"\n", imageId)
	result += fmt.Sprintf("MOUNT_POINT=\"%s\"\n", mountPoint)
	result += fmt.Sprintf("FILE_NAME=\"%s\"\n", FrontgateConfFile)
	result += fmt.Sprintf("FILE_CONF=%s\n", frontgateConfStr)

	return result
}

func (f *Frontgate) getCertificateExec() string {
	var pilotClientTLSConfig *types.PilotClientTLSConfig

	err := retryutil.Retry(3, constants.RetryInterval, func() error {
		pilotClient, err := pilotclient.NewClient()
		if err != nil {
			return err
		}
		pilotClientTLSConfig, err = pilotClient.GetPilotClientTLSConfig(f.Ctx, &metadatatypes.Empty{})
		if err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		logger.Critical(f.Ctx, "Get pilot client tls config failed, %+v", err)
		return ""
	}

	exec := fmt.Sprintf(`
echo '%s' > /opt/openpitrix/conf/openpitrix-ca.crt
echo '%s' > /opt/openpitrix/conf/pilot-client.crt
echo '%s' > /opt/openpitrix/conf/pilot-client.key
`, pilotClientTLSConfig.CaCrtData, pilotClientTLSConfig.ClientCrtData, pilotClientTLSConfig.ClientKeyData)

	return exec
}

func (f *Frontgate) pingFrontgateLayer(failureAllowed bool) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)

	directive := jsonutil.ToString(&models.Meta{
		ClusterId: f.ClusterWrapper.Cluster.ClusterId,
	})

	task := &models.Task{
		JobId:          f.Job.JobId,
		Owner:          f.Job.Owner,
		TaskAction:     ActionPingFrontgate,
		Target:         constants.TargetPilot,
		NodeId:         f.ClusterWrapper.Cluster.ClusterId,
		Directive:      directive,
		FailureAllowed: failureAllowed,
	}
	taskLayer.Tasks = append(taskLayer.Tasks, task)
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) setFrontgateConfigLayer(nodeIds []string, failureAllowed bool) *models.TaskLayer {
	var tasks []*models.Task
	directive := jsonutil.ToString(&models.Meta{
		ClusterId: f.ClusterWrapper.Cluster.ClusterId,
	})

	for _, nodeId := range nodeIds {
		// get frontgate config when pre task
		task := &models.Task{
			JobId:          f.Job.JobId,
			Owner:          f.Job.Owner,
			TaskAction:     ActionSetFrontgateConfig,
			Target:         constants.TargetPilot,
			NodeId:         nodeId,
			Directive:      directive,
			FailureAllowed: failureAllowed,
		}
		tasks = append(tasks, task)
	}
	return &models.TaskLayer{
		Tasks: tasks,
	}
}

func (f *Frontgate) pingMetadataBackendLayer(failureAllowed bool) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)

	directive := jsonutil.ToString(&models.Meta{
		ClusterId: f.ClusterWrapper.Cluster.ClusterId,
	})

	task := &models.Task{
		JobId:          f.Job.JobId,
		Owner:          f.Job.Owner,
		TaskAction:     PingMetadataBackend,
		Target:         constants.TargetPilot,
		NodeId:         f.ClusterWrapper.Cluster.ClusterId,
		Directive:      directive,
		FailureAllowed: failureAllowed,
	}
	taskLayer.Tasks = append(taskLayer.Tasks, task)
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) removeContainerLayer(nodeIds []string, failureAllowed bool) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)

	for nodeId, clusterNode := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		ip := clusterNode.PrivateIp
		cmd := fmt.Sprintf("%s \"docker rm -f default\"", HostCmdPrefix)
		request := &pbtypes.RunCommandOnFrontgateRequest{
			Endpoint: &pbtypes.FrontgateEndpoint{
				FrontgateId:     f.ClusterWrapper.Cluster.ClusterId,
				FrontgateNodeId: nodeId,
				NodeIp:          ip,
				NodePort:        constants.FrontgateServicePort,
			},
			Command:        cmd,
			TimeoutSeconds: TimeoutRemoveContainer,
		}
		directive := jsonutil.ToString(request)
		formatVolumeTask := &models.Task{
			JobId:          f.Job.JobId,
			Owner:          f.Job.Owner,
			TaskAction:     ActionRemoveContainerOnFrontgate,
			Target:         constants.TargetPilot,
			NodeId:         nodeId,
			Directive:      directive,
			FailureAllowed: failureAllowed,
		}
		taskLayer.Tasks = append(taskLayer.Tasks, formatVolumeTask)
	}
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) attachKeyPairLayer(nodeKeyPairDetail *models.NodeKeyPairDetail) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)
	clusterNode := nodeKeyPairDetail.ClusterNode
	request := &pbtypes.RunCommandOnFrontgateRequest{
		Endpoint: &pbtypes.FrontgateEndpoint{
			FrontgateId:     f.ClusterWrapper.Cluster.ClusterId,
			FrontgateNodeId: clusterNode.NodeId,
			NodeIp:          clusterNode.PrivateIp,
			NodePort:        constants.FrontgateServicePort,
		},
		Command:        fmt.Sprintf("%s \"%s\"", HostCmdPrefix, sshutil.DoAttachCmd(nodeKeyPairDetail.KeyPair.PubKey)),
		TimeoutSeconds: TimeoutKeyPair,
	}
	directive := jsonutil.ToString(request)
	attachKeyPairTask := &models.Task{
		JobId:          f.Job.JobId,
		Owner:          f.Job.Owner,
		TaskAction:     ActionRunCommandOnFrontgateNode,
		Target:         constants.TargetPilot,
		NodeId:         clusterNode.NodeId,
		Directive:      directive,
		FailureAllowed: false,
	}
	taskLayer.Tasks = append(taskLayer.Tasks, attachKeyPairTask)
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) detachKeyPairLayer(nodeKeyPairDetail *models.NodeKeyPairDetail) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)
	clusterNode := nodeKeyPairDetail.ClusterNode
	request := &pbtypes.RunCommandOnFrontgateRequest{
		Endpoint: &pbtypes.FrontgateEndpoint{
			FrontgateId:     f.ClusterWrapper.Cluster.ClusterId,
			FrontgateNodeId: clusterNode.NodeId,
			NodeIp:          clusterNode.PrivateIp,
			NodePort:        constants.FrontgateServicePort,
		},
		Command:        fmt.Sprintf("%s \"%s\"", HostCmdPrefix, sshutil.DoDetachCmd(nodeKeyPairDetail.KeyPair.PubKey)),
		TimeoutSeconds: TimeoutKeyPair,
	}
	directive := jsonutil.ToString(request)
	attachKeyPairTask := &models.Task{
		JobId:          f.Job.JobId,
		Owner:          f.Job.Owner,
		TaskAction:     ActionRunCommandOnFrontgateNode,
		Target:         constants.TargetPilot,
		NodeId:         clusterNode.NodeId,
		Directive:      directive,
		FailureAllowed: false,
	}
	taskLayer.Tasks = append(taskLayer.Tasks, attachKeyPairTask)
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) CreateClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	headTaskLayer.
		Append(f.createVolumesLayer(nodeIds, false)).        // create volume
		Append(f.runInstancesLayer(nodeIds, false)).         // run instance and attach volume to instance
		Append(f.pingFrontgateLayer(false)).                 // ping frontgate
		Append(f.formatAndMountVolumeLayer(nodeIds, false)). // format and mount volume to instance
		Append(f.removeContainerLayer(nodeIds, false)).      // remove default container
		Append(f.pingFrontgateLayer(false)).                 // ping frontgate
		Append(f.setFrontgateConfigLayer(nodeIds, false)).   // set frontgate config
		Append(f.pingMetadataBackendLayer(false))            // ping metadata backend

	return headTaskLayer.Child
}

func (f *Frontgate) DeleteClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	if f.ClusterWrapper.Cluster.Status == constants.StatusActive {
		headTaskLayer.
			Append(f.umountVolumeLayer(nodeIds, true)).  // umount volume from instance
			Append(f.stopInstancesLayer(nodeIds, true)). // stop instance
			Append(f.detachVolumesLayer(nodeIds, false)) // detach volume from instance
	}

	headTaskLayer.
		Append(f.deleteInstancesLayer(nodeIds, false)). // delete instance
		Append(f.deleteVolumesLayer(nodeIds, false))    // delete volume
	return headTaskLayer.Child
}

func (f *Frontgate) StartClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	headTaskLayer.
		Append(f.attachVolumesLayer(nodeIds, false)).      // attach volume to instance, will auto mount
		Append(f.startInstancesLayer(nodeIds, false)).     // run instance and attach volume to instance
		Append(f.pingFrontgateLayer(false)).               // ping frontgate
		Append(f.setFrontgateConfigLayer(nodeIds, false)). // set frontgate config
		Append(f.pingMetadataBackendLayer(false))          // ping metadata backend

	return headTaskLayer.Child
}

func (f *Frontgate) StopClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	headTaskLayer.
		Append(f.umountVolumeLayer(nodeIds, true)).   // umount volume from instance
		Append(f.stopInstancesLayer(nodeIds, false)). // delete instance
		Append(f.detachVolumesLayer(nodeIds, false))  // detach volume from instance

	return headTaskLayer.Child
}

func (f *Frontgate) AttachKeyPairsLayer(nodeKeyPairDetails models.NodeKeyPairDetails) *models.TaskLayer {
	headTaskLayer := new(models.TaskLayer)

	for _, nodeKeyPairDetail := range nodeKeyPairDetails {
		headTaskLayer.Append(f.attachKeyPairLayer(&nodeKeyPairDetail))
	}

	return headTaskLayer.Child
}

func (f *Frontgate) DetachKeyPairsLayer(nodeKeyPairDetails models.NodeKeyPairDetails) *models.TaskLayer {
	headTaskLayer := new(models.TaskLayer)

	for _, nodeKeyPairDetail := range nodeKeyPairDetails {
		headTaskLayer.Append(f.detachKeyPairLayer(&nodeKeyPairDetail))
	}

	return headTaskLayer.Child
}
<|endoftext|>


<commit_before>/*
Copyright 2017 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 hostpath

import (
	"fmt"
	"os"
	"os/exec"

	"k8s.io/apimachinery/pkg/util/uuid"
	"k8s.io/client-go/pkg/api/v1"

	tprv1 "github.com/rootfs/snapshot/pkg/apis/tpr/v1"
	"github.com/rootfs/snapshot/pkg/cloudprovider"
	"github.com/rootfs/snapshot/pkg/volume"
)

const (
	depot        = "/tmp/"
	restorePoint = "/restore/"
)

type hostPathPlugin struct {
}

var _ volume.VolumePlugin = &hostPathPlugin{}

func RegisterPlugin() volume.VolumePlugin {
	return &hostPathPlugin{}
}

func GetPluginName() string {
	return "hostPath"
}

func (h *hostPathPlugin) Init(_ cloudprovider.Interface) {
}

func (h *hostPathPlugin) SnapshotCreate(pv *v1.PersistentVolume) (*tprv1.VolumeSnapshotDataSource, error) {
	spec := &pv.Spec
	if spec == nil || spec.HostPath == nil {
		return nil, fmt.Errorf("invalid PV spec %v", spec)
	}
	path := spec.HostPath.Path
	file := depot + string(uuid.NewUUID()) + ".tgz"
	cmd := exec.Command("tar", "czvf", file, path)
	res := &tprv1.VolumeSnapshotDataSource{
		HostPath: &tprv1.HostPathVolumeSnapshotSource{
			Path: file,
		},
	}
	return res, cmd.Run()
}

func (h *hostPathPlugin) SnapshotDelete(src *tprv1.VolumeSnapshotDataSource, _ *v1.PersistentVolume) error {
	if src == nil || src.HostPath == nil {
		return fmt.Errorf("invalid VolumeSnapshotDataSource: %v", src)
	}
	path := src.HostPath.Path
	return os.Remove(path)
}

func (a *hostPathPlugin) DescribeSnapshot(snapshotData *tprv1.VolumeSnapshotData) (isCompleted bool, err error) {
	if snapshotData == nil || snapshotData.Spec.HostPath == nil {
		return false, fmt.Errorf("failed to retrieve Snapshot spec")
	}
	path := snapshotData.Spec.HostPath.Path
	if _, err := os.Stat(path); err != nil {
		return false, err
	}
	return true, nil
}

func (h *hostPathPlugin) SnapshotRestore(snapshotData *tprv1.VolumeSnapshotData, _ *v1.PersistentVolumeClaim, _ string, _ map[string]string) (*v1.PersistentVolumeSource, map[string]string, error) {
	// retrieve VolumeSnapshotDataSource
	if snapshotData == nil || snapshotData.Spec.HostPath == nil {
		return nil, nil, fmt.Errorf("failed to retrieve Snapshot spec")
	}
	// restore snapshot to a PV
	snapId := snapshotData.Spec.HostPath.Path
	dir := restorePoint + string(uuid.NewUUID())
	os.MkdirAll(dir, 0750)
	cmd := exec.Command("tar", "xzvf", snapId, "-C", dir)
	err := cmd.Run()
	if err != nil {
		return nil, nil, fmt.Errorf("failed to restore %s to %s: %v", snapId, dir, err)
	}
	pv := &v1.PersistentVolumeSource{
		HostPath: &v1.HostPathVolumeSource{
			Path: dir,
		},
	}
	return pv, nil, nil
}

func (h *hostPathPlugin) VolumeDelete(pv *v1.PersistentVolume) error {
	if pv == nil || pv.Spec.HostPath == nil {
		return fmt.Errorf("invalid VolumeSnapshotDataSource: %v", pv)
	}
	path := pv.Spec.HostPath.Path
	return os.Remove(path)

}
<commit_msg>remove top level directory in hostpath snapshot restore<commit_after>/*
Copyright 2017 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 hostpath

import (
	"fmt"
	"os"
	"os/exec"

	"k8s.io/apimachinery/pkg/util/uuid"
	"k8s.io/client-go/pkg/api/v1"

	tprv1 "github.com/rootfs/snapshot/pkg/apis/tpr/v1"
	"github.com/rootfs/snapshot/pkg/cloudprovider"
	"github.com/rootfs/snapshot/pkg/volume"
)

const (
	depot        = "/tmp/"
	restorePoint = "/restore/"
)

type hostPathPlugin struct {
}

var _ volume.VolumePlugin = &hostPathPlugin{}

func RegisterPlugin() volume.VolumePlugin {
	return &hostPathPlugin{}
}

func GetPluginName() string {
	return "hostPath"
}

func (h *hostPathPlugin) Init(_ cloudprovider.Interface) {
}

func (h *hostPathPlugin) SnapshotCreate(pv *v1.PersistentVolume) (*tprv1.VolumeSnapshotDataSource, error) {
	spec := &pv.Spec
	if spec == nil || spec.HostPath == nil {
		return nil, fmt.Errorf("invalid PV spec %v", spec)
	}
	path := spec.HostPath.Path
	file := depot + string(uuid.NewUUID()) + ".tgz"
	cmd := exec.Command("tar", "czf", file, path)
	res := &tprv1.VolumeSnapshotDataSource{
		HostPath: &tprv1.HostPathVolumeSnapshotSource{
			Path: file,
		},
	}
	return res, cmd.Run()
}

func (h *hostPathPlugin) SnapshotDelete(src *tprv1.VolumeSnapshotDataSource, _ *v1.PersistentVolume) error {
	if src == nil || src.HostPath == nil {
		return fmt.Errorf("invalid VolumeSnapshotDataSource: %v", src)
	}
	path := src.HostPath.Path
	return os.Remove(path)
}

func (a *hostPathPlugin) DescribeSnapshot(snapshotData *tprv1.VolumeSnapshotData) (isCompleted bool, err error) {
	if snapshotData == nil || snapshotData.Spec.HostPath == nil {
		return false, fmt.Errorf("failed to retrieve Snapshot spec")
	}
	path := snapshotData.Spec.HostPath.Path
	if _, err := os.Stat(path); err != nil {
		return false, err
	}
	return true, nil
}

func (h *hostPathPlugin) SnapshotRestore(snapshotData *tprv1.VolumeSnapshotData, _ *v1.PersistentVolumeClaim, _ string, _ map[string]string) (*v1.PersistentVolumeSource, map[string]string, error) {
	// retrieve VolumeSnapshotDataSource
	if snapshotData == nil || snapshotData.Spec.HostPath == nil {
		return nil, nil, fmt.Errorf("failed to retrieve Snapshot spec")
	}
	// restore snapshot to a PV
	snapId := snapshotData.Spec.HostPath.Path
	dir := restorePoint + string(uuid.NewUUID())
	os.MkdirAll(dir, 0750)
	cmd := exec.Command("tar", "xzf", snapId, "-C", dir, "--strip-components=1")
	err := cmd.Run()
	if err != nil {
		return nil, nil, fmt.Errorf("failed to restore %s to %s: %v", snapId, dir, err)
	}
	pv := &v1.PersistentVolumeSource{
		HostPath: &v1.HostPathVolumeSource{
			Path: dir,
		},
	}
	return pv, nil, nil
}

func (h *hostPathPlugin) VolumeDelete(pv *v1.PersistentVolume) error {
	if pv == nil || pv.Spec.HostPath == nil {
		return fmt.Errorf("invalid VolumeSnapshotDataSource: %v", pv)
	}
	path := pv.Spec.HostPath.Path
	return os.Remove(path)

}
<|endoftext|>


<commit_before>// Copyright 2015 Bowery, Inc.

package ignores

import (
	"bufio"
	"os"
	"path/filepath"
)

var (
	// VersionControlSystems is a list of version control system directories
	// that should be ignored.
	VersionControlSystems = []string{".hg", ".git", ".svn", ".bzr"}
)

// Get retrieves a list of files to ignore in a given directory.
// A set of default ignores may be given.
func Get(path string, ignores ...string) ([]string, error) {
	var matches []string

	file, err := os.Open(path)
	if err != nil && !os.IsNotExist(err) {
		return nil, err
	}

	if file != nil {
		defer file.Close()
		scanner := bufio.NewScanner(file)

		for scanner.Scan() {
			ignores = append(ignores, scanner.Text())
		}

		err := scanner.Err()
		if err != nil {
			return nil, err
		}
	}

	for _, ignore := range ignores {
		ignoreMatches, err := filepath.Glob(filepath.Join(path, "..", ignore))
		if err != nil {
			return nil, err
		}

		matches = append(matches, ignoreMatches...)
	}

	return matches, nil
}
<commit_msg>Fix if default ignores are empty.<commit_after>// Copyright 2015 Bowery, Inc.

package ignores

import (
	"bufio"
	"os"
	"path/filepath"
)

var (
	// VersionControlSystems is a list of version control system directories
	// that should be ignored.
	VersionControlSystems = []string{".hg", ".git", ".svn", ".bzr"}
)

// Get retrieves a list of paths to ignore in the directory the given ignore
// file lives in. A set of default ignores may be given.
func Get(path string, ignores ...string) ([]string, error) {
	var matches []string
	if ignores == nil {
		ignores = make([]string, 0)
	}

	file, err := os.Open(path)
	if err != nil && !os.IsNotExist(err) {
		return nil, err
	}

	if file != nil {
		defer file.Close()
		scanner := bufio.NewScanner(file)

		for scanner.Scan() {
			ignores = append(ignores, scanner.Text())
		}

		err := scanner.Err()
		if err != nil {
			return nil, err
		}
	}

	for _, ignore := range ignores {
		ignoreMatches, err := filepath.Glob(filepath.Join(filepath.Dir(path), ignore))
		if err != nil {
			return nil, err
		}

		matches = append(matches, ignoreMatches...)
	}

	return matches, nil
}
<|endoftext|>