Replace entrypoint script with initcontainers (#718)

* build: install the multus binary in an init container

Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>

* build: generate kubeconfig via go

Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>

* build: generate multus cni configuration via golang

Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>

* build: provide a docker img for daemon based deployments

We will have 2 different images (only on amd64 archs):
- legacy entrypoint script based
- daemonized process

The `image-build` docker action is updated, to build these 2 images.

There will be 2 different deployment specs, along with e2e test
lanes, one for each of the aforementioned alternatives.

Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>

* build: delegate CNI config watch loop via golang

For the thick-plugin alternative, provide the watch loop for
configuration regeneration via a golang binary.

Over time, this binary is expected to run the control loop to watch
out for pod updates.

To enable current multus users to chose when they upgrade to this new
deployment setup, these changes are provided in separate multus images,
having a different yaml spec files. Both of these alternatives are
tested e2e, since a new lane is introduced.

The following libraries are introduced, along with the motivation for
adding them:
- dproxy: allows traversing the default network configuration arbitrarily,
  similar to what an X path / JSON path tool provides.
  Repo is available at [0].
- fsnotify: watch for changes in the default CNI configuration file.
  Repo is available at [1].

The config map providing the default network CNI configuration is not
copied over, since originally, the user was not required to install a
default network CNI plugin first, but, nowadays, this is a required
step of multus.

As such, it is no longer required to provide a default CNI
configuration.

[0] - https://github.com/koron/go-dproxy
[1] - https://github.com/fsnotify/fsnotify

Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>

* run gofmt

Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>

* refactor: make the builder pattern more idiomatic to golang

Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>

* build: update github actions to release new imgs

Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>
This commit is contained in:
Miguel Duarte Barroso
2021-10-27 14:42:37 +02:00
committed by GitHub
parent b56dd5f67f
commit 8ba2accb9f
39 changed files with 3138 additions and 197 deletions

2
vendor/github.com/koron/go-dproxy/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,2 @@
/tags
/tmp/

21
vendor/github.com/koron/go-dproxy/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 MURAOKA Taro <koron.kaoriya@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

29
vendor/github.com/koron/go-dproxy/Makefile generated vendored Normal file
View File

@@ -0,0 +1,29 @@
default: test
test:
go test ./...
test-full:
go test -v -race ./...
lint:
go vet ./...
@echo ""
golint ./...
cyclo:
-gocyclo -top 10 -avg .
report:
@echo "misspell"
@find . -name "*.go" | xargs misspell
@echo ""
-errcheck ./...
@echo ""
-gocyclo -over 14 -avg .
@echo ""
go vet ./...
@echo ""
golint ./...
.PHONY: test test-full lint cyclo report

155
vendor/github.com/koron/go-dproxy/README.md generated vendored Normal file
View File

@@ -0,0 +1,155 @@
# dProxy - document proxy
[![GoDoc](https://godoc.org/github.com/koron/go-dproxy?status.svg)](https://godoc.org/github.com/koron/go-dproxy)
[![CircleCI](https://img.shields.io/circleci/project/github/koron/go-dproxy/master.svg)](https://circleci.com/gh/koron/go-dproxy/tree/master)
[![Go Report Card](https://goreportcard.com/badge/github.com/koron/go-dproxy)](https://goreportcard.com/report/github.com/koron/go-dproxy)
dProxy is a proxy to access `interface{}` (document) by simple query.
It is intented to be used with `json.Unmarshal()` or `json.NewDecorder()`.
See codes for overview.
```go
import (
"encoding/json"
"github.com/koron/go-dproxy"
)
var v interface{}
json.Unmarshal([]byte(`{
"cities": [ "tokyo", 100, "osaka", 200, "hakata", 300 ],
"data": {
"custom": [ "male", 23, "female", 24 ]
}
}`), &v)
// s == "tokyo", got a string.
s, _ := dproxy.New(v).M("cities").A(0).String()
// err != nil, type not matched.
_, err := dproxy.New(v).M("cities").A(0).Float64()
// n == 200, got a float64
n, _ := dproxy.New(v).M("cities").A(3).Float64()
// can be chained.
dproxy.New(v).M("data").M("custom").A(0).String()
// err.Error() == "not found: data.kustom", wrong query can be verified.
_, err = dproxy.New(v).M("data").M("kustom").String()
```
## Getting started
### Proxy
1. Wrap a value (`interface{}`) with `dproxy.New()` get `dproxy.Proxy`.
```go
p := dproxy.New(v) // v should be a value of interface{}
```
2. Query as a map (`map[string]interface{}`)by `M()`, returns `dproxy.Proxy`.
```go
p.M("cities")
```
3. Query as an array (`[]interface{}`) with `A()`, returns `dproxy.Proxy`.
```go
p.A(3)
```
4. Therefore, can be chained queries.
```go
p.M("cities").A(3)
```
5. Get a value finally.
```go
n, _ := p.M("cities").A(3).Int64()
```
6. You'll get an error when getting a value, if there were some mistakes.
```go
// OOPS! "kustom" is typo, must be "custom"
_, err := p.M("data").M("kustom").A(3).Int64()
// "not found: data.kustom"
fmt.Println(err)
```
7. If you tried to get a value as different type, get an error.
```go
// OOPS! "cities[3]" (=200) should be float64 or int64.
_, err := p.M("cities").A(3).String()
// "not matched types: expected=string actual=float64: cities[3]"
fmt.Println(err)
```
8. You can verify queries easily.
### Drain
Getting value and error from Proxy/ProxySet multiple times, is very awful.
It must check error when every getting values.
```go
p := dproxy.New(v)
v1, err := p.M("cities").A(3).Int64()
if err != nil {
return err
}
v2, err := p.M("data").M("kustom").A(3).Int64()
if err != nil {
return err
}
v3, err := p.M("cities").A(3).String()
if err != nil {
return err
}
```
It can be rewrite as simple like below with `dproxy.Drain`
```go
var d Drain
p := dproxy.New(v)
v1 := d.Int64(p.M("cities").A(3))
v2 := d.Int64(p.M("data").M("kustom").A(3))
v3 := d.String(p.M("cities").A(3))
if err := d.CombineErrors(); err != nil {
return err
}
```
### JSON Pointer
JSON Pointer can be used to query `interface{}`
```go
v1, err := dproxy.New(v).P("/cities/0").Int64()
```
or
```go
v1, err := dproxy.Pointer(v, "/cities/0").Int64()
```
See [RFC6901][1] for details of JSON Pointer.
## LICENSE
MIT license. See LICENSE.
[1]: https://tools.ietf.org/html/rfc6901

150
vendor/github.com/koron/go-dproxy/drain.go generated vendored Normal file
View File

@@ -0,0 +1,150 @@
package dproxy
import "bytes"
// Drain stores errors from Proxy or ProxySet.
type Drain struct {
errors []error
}
// Has returns true if the drain stored some of errors.
func (d *Drain) Has() bool {
return d != nil && len(d.errors) > 0
}
// First returns a stored error. Returns nil if there are no errors.
func (d *Drain) First() error {
if d == nil || len(d.errors) == 0 {
return nil
}
return d.errors[0]
}
// All returns all errors which stored. Return nil if no errors stored.
func (d *Drain) All() []error {
if d == nil || len(d.errors) == 0 {
return nil
}
a := make([]error, 0, len(d.errors))
return append(a, d.errors...)
}
// CombineErrors returns an error which combined all stored errors. Return nil
// if not erros stored.
func (d *Drain) CombineErrors() error {
if d == nil || len(d.errors) == 0 {
return nil
}
return drainError(d.errors)
}
func (d *Drain) put(err error) {
if err == nil {
return
}
d.errors = append(d.errors, err)
}
// Bool returns bool value and stores an error.
func (d *Drain) Bool(p Proxy) bool {
v, err := p.Bool()
d.put(err)
return v
}
// Int64 returns int64 value and stores an error.
func (d *Drain) Int64(p Proxy) int64 {
v, err := p.Int64()
d.put(err)
return v
}
// Float64 returns float64 value and stores an error.
func (d *Drain) Float64(p Proxy) float64 {
v, err := p.Float64()
d.put(err)
return v
}
// String returns string value and stores an error.
func (d *Drain) String(p Proxy) string {
v, err := p.String()
d.put(err)
return v
}
// Array returns []interface{} value and stores an error.
func (d *Drain) Array(p Proxy) []interface{} {
v, err := p.Array()
d.put(err)
return v
}
// Map returns map[string]interface{} value and stores an error.
func (d *Drain) Map(p Proxy) map[string]interface{} {
v, err := p.Map()
d.put(err)
return v
}
// BoolArray returns []bool value and stores an error.
func (d *Drain) BoolArray(ps ProxySet) []bool {
v, err := ps.BoolArray()
d.put(err)
return v
}
// Int64Array returns []int64 value and stores an error.
func (d *Drain) Int64Array(ps ProxySet) []int64 {
v, err := ps.Int64Array()
d.put(err)
return v
}
// Float64Array returns []float64 value and stores an error.
func (d *Drain) Float64Array(ps ProxySet) []float64 {
v, err := ps.Float64Array()
d.put(err)
return v
}
// StringArray returns []string value and stores an error.
func (d *Drain) StringArray(ps ProxySet) []string {
v, err := ps.StringArray()
d.put(err)
return v
}
// ArrayArray returns [][]interface{} value and stores an error.
func (d *Drain) ArrayArray(ps ProxySet) [][]interface{} {
v, err := ps.ArrayArray()
d.put(err)
return v
}
// MapArray returns []map[string]interface{} value and stores an error.
func (d *Drain) MapArray(ps ProxySet) []map[string]interface{} {
v, err := ps.MapArray()
d.put(err)
return v
}
// ProxyArray returns []Proxy value and stores an error.
func (d *Drain) ProxyArray(ps ProxySet) []Proxy {
v, err := ps.ProxyArray()
d.put(err)
return v
}
type drainError []error
func (derr drainError) Error() string {
b := bytes.Buffer{}
for i, err := range derr {
if i > 0 {
_, _ = b.WriteString("; ")
}
_, _ = b.WriteString(err.Error())
}
return b.String()
}

253
vendor/github.com/koron/go-dproxy/error.go generated vendored Normal file
View File

@@ -0,0 +1,253 @@
package dproxy
import (
"fmt"
"strconv"
)
// ErrorType is type of errors
type ErrorType int
const (
// Etype means expected type is not matched with actual.
Etype ErrorType = iota + 1
// Enotfound means key or index doesn't exist.
Enotfound
// EmapNorArray means target is not a map nor an array (for JSON Pointer)
EmapNorArray
// EconvertFailure means value conversion is failed.
EconvertFailure
// EinvalidIndex means token is invalid as index (for JSON Pointer)
EinvalidIndex
// EinvalidQuery means query is invalid as JSON Pointer.
EinvalidQuery
// ErequiredType means the type mismatch against user required one.
// For example M() requires map, A() requires array.
ErequiredType
)
func (et ErrorType) String() string {
switch et {
case Etype:
return "Etype"
case Enotfound:
return "Enotfound"
case EmapNorArray:
return "EmapNorArray"
case EconvertFailure:
return "EconvertFailure"
case EinvalidIndex:
return "EinvalidIndex"
case EinvalidQuery:
return "EinvalidQuery"
case ErequiredType:
return "ErequiredType"
default:
return "Eunknown"
}
}
// Error get detail information of the errror.
type Error interface {
// ErrorType returns type of error.
ErrorType() ErrorType
// FullAddress returns query string where cause first error.
FullAddress() string
}
type errorProxy struct {
errorType ErrorType
parent frame
label string
expected Type
actual Type
infoStr string
}
// errorProxy implements error, Proxy and ProxySet.
var (
_ error = (*errorProxy)(nil)
_ Proxy = (*errorProxy)(nil)
_ ProxySet = (*errorProxy)(nil)
)
func (p *errorProxy) Nil() bool {
return false
}
func (p *errorProxy) Value() (interface{}, error) {
return nil, p
}
func (p *errorProxy) Bool() (bool, error) {
return false, p
}
func (p *errorProxy) Int64() (int64, error) {
return 0, p
}
func (p *errorProxy) Float64() (float64, error) {
return 0, p
}
func (p *errorProxy) String() (string, error) {
return "", p
}
func (p *errorProxy) Array() ([]interface{}, error) {
return nil, p
}
func (p *errorProxy) Map() (map[string]interface{}, error) {
return nil, p
}
func (p *errorProxy) A(n int) Proxy {
return p
}
func (p *errorProxy) M(k string) Proxy {
return p
}
func (p *errorProxy) P(q string) Proxy {
return p
}
func (p *errorProxy) Empty() bool {
return true
}
func (p *errorProxy) Len() int {
return 0
}
func (p *errorProxy) BoolArray() ([]bool, error) {
return nil, p
}
func (p *errorProxy) Int64Array() ([]int64, error) {
return nil, p
}
func (p *errorProxy) Float64Array() ([]float64, error) {
return nil, p
}
func (p *errorProxy) StringArray() ([]string, error) {
return nil, p
}
func (p *errorProxy) ArrayArray() ([][]interface{}, error) {
return nil, p
}
func (p *errorProxy) MapArray() ([]map[string]interface{}, error) {
return nil, p
}
func (p *errorProxy) ProxyArray() ([]Proxy, error) {
return nil, p
}
func (p *errorProxy) ProxySet() ProxySet {
return p
}
func (p *errorProxy) Q(k string) ProxySet {
return p
}
func (p *errorProxy) Qc(k string) ProxySet {
return p
}
func (p *errorProxy) findJPT(t string) Proxy {
return p
}
func (p *errorProxy) parentFrame() frame {
return p.parent
}
func (p *errorProxy) frameLabel() string {
return p.label
}
func (p *errorProxy) Error() string {
switch p.errorType {
case Etype:
return fmt.Sprintf("not matched types: expected=%s actual=%s: %s",
p.expected.String(), p.actual.String(), p.FullAddress())
case Enotfound:
return fmt.Sprintf("not found: %s", p.FullAddress())
case EmapNorArray:
// FIXME: better error message.
return fmt.Sprintf("not map nor array: actual=%s: %s",
p.actual.String(), p.FullAddress())
case EconvertFailure:
return fmt.Sprintf("convert error: %s: %s", p.infoStr, p.FullAddress())
case EinvalidIndex:
// FIXME: better error message.
return fmt.Sprintf("invalid index: %s: %s", p.infoStr, p.FullAddress())
case EinvalidQuery:
// FIXME: better error message.
return fmt.Sprintf("invalid query: %s: %s", p.infoStr, p.FullAddress())
case ErequiredType:
return fmt.Sprintf("not required types: required=%s actual=%s: %s",
p.expected.String(), p.actual.String(), p.FullAddress())
default:
return fmt.Sprintf("unexpected: %s", p.FullAddress())
}
}
func (p *errorProxy) ErrorType() ErrorType {
return p.errorType
}
func (p *errorProxy) FullAddress() string {
return fullAddress(p)
}
func typeError(p frame, expected Type, actual interface{}) *errorProxy {
return &errorProxy{
errorType: Etype,
parent: p,
expected: expected,
actual: detectType(actual),
}
}
func requiredTypeError(p frame, expected Type, actual interface{}) *errorProxy {
return &errorProxy{
errorType: ErequiredType,
parent: p,
expected: expected,
actual: detectType(actual),
}
}
func elementTypeError(p frame, index int, expected Type, actual interface{}) *errorProxy {
q := &simpleFrame{
parent: p,
label: "[" + strconv.Itoa(index) + "]",
}
return typeError(q, expected, actual)
}
func notfoundError(p frame, address string) *errorProxy {
return &errorProxy{
errorType: Enotfound,
parent: p,
label: address,
}
}

42
vendor/github.com/koron/go-dproxy/frame.go generated vendored Normal file
View File

@@ -0,0 +1,42 @@
package dproxy
type frame interface {
// parentFrame returns parent frame.
parentFrame() frame
// frameLabel return label of frame.
frameLabel() string
}
func fullAddress(f frame) string {
x := 0
for g := f; g != nil; g = g.parentFrame() {
x += len(g.frameLabel())
}
if x == 0 {
return "(root)"
}
b := make([]byte, x)
for g := f; g != nil; g = g.parentFrame() {
x -= len(g.frameLabel())
copy(b[x:], g.frameLabel())
}
if b[0] == '.' {
return string(b[1:])
}
return string(b)
}
type simpleFrame struct {
parent frame
label string
}
var _ frame = (*simpleFrame)(nil)
func (f *simpleFrame) parentFrame() frame {
return f.parent
}
func (f *simpleFrame) frameLabel() string {
return f.label
}

3
vendor/github.com/koron/go-dproxy/go.mod generated vendored Normal file
View File

@@ -0,0 +1,3 @@
module github.com/koron/go-dproxy
go 1.13

0
vendor/github.com/koron/go-dproxy/go.sum generated vendored Normal file
View File

31
vendor/github.com/koron/go-dproxy/pointer.go generated vendored Normal file
View File

@@ -0,0 +1,31 @@
package dproxy
import "strings"
var jptR = strings.NewReplacer("~1", "/", "~0", "~")
func unescapeJPT(t string) string {
return jptR.Replace(t)
}
func pointer(p Proxy, q string) Proxy {
if len(q) == 0 {
return p
}
if q[0] != '/' {
return &errorProxy{
errorType: EinvalidQuery,
parent: p,
infoStr: "not start with '/'",
}
}
for _, t := range strings.Split(q[1:], "/") {
p = p.findJPT(unescapeJPT(t))
}
return p
}
// Pointer returns a Proxy which pointed by JSON Pointer's query q
func Pointer(v interface{}, q string) Proxy {
return pointer(New(v), q)
}

102
vendor/github.com/koron/go-dproxy/proxy.go generated vendored Normal file
View File

@@ -0,0 +1,102 @@
package dproxy
// Proxy is a proxy to access a document (interface{}).
type Proxy interface {
// Nil returns true, if target value is nil.
Nil() bool
// Value returns a proxied value. If there are no values, it returns
// error.
Value() (interface{}, error)
// Bool returns its value. If value isn't the type, it returns error.
Bool() (bool, error)
// Int64 returns its value. If value isn't the type, it returns error.
Int64() (int64, error)
// Float64 returns its value. If value isn't the type, it returns error.
Float64() (float64, error)
// String returns its value. If value isn't the type, it returns error.
String() (string, error)
// Array returns its value. If value isn't the type, it returns error.
Array() ([]interface{}, error)
// Map returns its value. If value isn't the type, it returns error.
Map() (map[string]interface{}, error)
// A returns an item from value treated as the array.
A(n int) Proxy
// M returns an item from value treated as the map.
M(k string) Proxy
// P returns which pointed by JSON Pointer's query q.
P(q string) Proxy
// ProxySet returns a set which converted from its array value.
ProxySet() ProxySet
// Q returns set of all items which property matchs with k.
Q(k string) ProxySet
// findJPT returns a match of JSON Pointer's Token t.
findJPT(t string) Proxy
// Proxy implements frame.
frame
}
// ProxySet proxies to access to set.
type ProxySet interface {
// Empty returns true when the set is empty.
Empty() bool
// Len returns count of items in the set.
Len() int
// BoolArray returns []bool which converterd from the set.
BoolArray() ([]bool, error)
// Int64Array returns []int64 which converterd from the set.
Int64Array() ([]int64, error)
// Float64Array returns []float64 which converterd from the set.
Float64Array() ([]float64, error)
// StringArray returns []string which converterd from the set.
StringArray() ([]string, error)
// ArrayArray returns [][]interface{} which converterd from the set.
ArrayArray() ([][]interface{}, error)
// MapArray returns []map[string]interface{} which converterd from the set.
MapArray() ([]map[string]interface{}, error)
// ProxyArray returns []Proxy which wrap each items.
ProxyArray() ([]Proxy, error)
// A returns an proxy for index in the set.
A(n int) Proxy
// Q returns set of all items which property matchs with k.
Q(k string) ProxySet
// Qc returns set of property of all items.
Qc(k string) ProxySet
// Proxy implements frame.
frame
}
// New creates a new Proxy instance for v.
func New(v interface{}) Proxy {
return &valueProxy{value: v}
}
// NewSet create a new ProxySet instance for v.
func NewSet(v []interface{}) ProxySet {
return &setProxy{values: v}
}

193
vendor/github.com/koron/go-dproxy/set.go generated vendored Normal file
View File

@@ -0,0 +1,193 @@
package dproxy
import "strconv"
type setProxy struct {
values []interface{}
parent frame
label string
}
// setProxy implements ProxySet
var _ ProxySet = (*setProxy)(nil)
func (p *setProxy) Empty() bool {
return p.Len() == 0
}
func (p *setProxy) Len() int {
return len(p.values)
}
func (p *setProxy) BoolArray() ([]bool, error) {
r := make([]bool, len(p.values))
for i, v := range p.values {
switch v := v.(type) {
case bool:
r[i] = v
default:
return nil, elementTypeError(p, i, Tbool, v)
}
}
return r, nil
}
func (p *setProxy) Int64Array() ([]int64, error) {
r := make([]int64, len(p.values))
for i, v := range p.values {
switch v := v.(type) {
case int:
r[i] = int64(v)
case int32:
r[i] = int64(v)
case int64:
r[i] = v
case float32:
r[i] = int64(v)
case float64:
r[i] = int64(v)
default:
return nil, elementTypeError(p, i, Tint64, v)
}
}
return r, nil
}
func (p *setProxy) Float64Array() ([]float64, error) {
r := make([]float64, len(p.values))
for i, v := range p.values {
switch v := v.(type) {
case int:
r[i] = float64(v)
case int32:
r[i] = float64(v)
case int64:
r[i] = float64(v)
case float32:
r[i] = float64(v)
case float64:
r[i] = v
default:
return nil, elementTypeError(p, i, Tfloat64, v)
}
}
return r, nil
}
func (p *setProxy) StringArray() ([]string, error) {
r := make([]string, len(p.values))
for i, v := range p.values {
switch v := v.(type) {
case string:
r[i] = v
default:
return nil, elementTypeError(p, i, Tstring, v)
}
}
return r, nil
}
func (p *setProxy) ArrayArray() ([][]interface{}, error) {
r := make([][]interface{}, len(p.values))
for i, v := range p.values {
switch v := v.(type) {
case []interface{}:
r[i] = v
default:
return nil, elementTypeError(p, i, Tarray, v)
}
}
return r, nil
}
func (p *setProxy) MapArray() ([]map[string]interface{}, error) {
r := make([]map[string]interface{}, len(p.values))
for i, v := range p.values {
switch v := v.(type) {
case map[string]interface{}:
r[i] = v
default:
return nil, elementTypeError(p, i, Tmap, v)
}
}
return r, nil
}
func (p *setProxy) ProxyArray() ([]Proxy, error) {
r := make([]Proxy, 0, len(p.values))
for i, v := range p.values {
r = append(r, &valueProxy{
value: v,
parent: p,
label: "[" + strconv.Itoa(i) + "]",
})
}
return r, nil
}
func (p *setProxy) A(n int) Proxy {
a := "[" + strconv.Itoa(n) + "]"
if n < 0 || n >= len(p.values) {
return notfoundError(p, a)
}
return &valueProxy{
value: p.values[n],
parent: p,
label: a,
}
}
func (p *setProxy) Q(k string) ProxySet {
w := findAll(p.values, k)
return &setProxy{
values: w,
parent: p,
label: ".." + k,
}
}
func (p *setProxy) Qc(k string) ProxySet {
r := make([]interface{}, 0, len(p.values))
for _, v := range p.values {
switch v := v.(type) {
case map[string]interface{}:
if w, ok := v[k]; ok {
r = append(r, w)
}
}
}
return &setProxy{
values: r,
parent: p,
label: ".." + k,
}
}
func (p *setProxy) parentFrame() frame {
return p.parent
}
func (p *setProxy) frameLabel() string {
return p.label
}
func findAll(v interface{}, k string) []interface{} {
return findAllImpl(v, k, make([]interface{}, 0, 10))
}
func findAllImpl(v interface{}, k string, r []interface{}) []interface{} {
switch v := v.(type) {
case map[string]interface{}:
for n, w := range v {
if n == k {
r = append(r, w)
}
r = findAllImpl(w, k, r)
}
case []interface{}:
for _, w := range v {
r = findAllImpl(w, k, r)
}
}
return r
}

76
vendor/github.com/koron/go-dproxy/type.go generated vendored Normal file
View File

@@ -0,0 +1,76 @@
package dproxy
// Type is type of value.
type Type int
const (
// Tunknown shows value is not supported.
Tunknown Type = iota
// Tnil shows value is nil.
Tnil
// Tbool shows value is bool.
Tbool
// Tint64 shows value is int64.
Tint64
// Tfloat64 shows value is float64.
Tfloat64
// Tstring shows value is string.
Tstring
// Tarray shows value is an array ([]interface{})
Tarray
// Tmap shows value is a map (map[string]interface{})
Tmap
)
// detectType returns type of a value.
func detectType(v interface{}) Type {
if v == nil {
return Tnil
}
switch v.(type) {
case bool:
return Tbool
case int, int32, int64:
return Tint64
case float32, float64:
return Tfloat64
case string:
return Tstring
case []interface{}:
return Tarray
case map[string]interface{}:
return Tmap
default:
return Tunknown
}
}
func (t Type) String() string {
switch t {
case Tunknown:
return "unknown"
case Tnil:
return "nil"
case Tbool:
return "bool"
case Tint64:
return "int64"
case Tfloat64:
return "float64"
case Tstring:
return "string"
case Tarray:
return "array"
case Tmap:
return "map"
default:
return "unknown"
}
}

222
vendor/github.com/koron/go-dproxy/value.go generated vendored Normal file
View File

@@ -0,0 +1,222 @@
package dproxy
import (
"reflect"
"strconv"
)
type valueProxy struct {
value interface{}
parent frame
label string
}
// valueProxy implements Proxy.
var _ Proxy = (*valueProxy)(nil)
func (p *valueProxy) Nil() bool {
return p.value == nil
}
func (p *valueProxy) Value() (interface{}, error) {
return p.value, nil
}
func (p *valueProxy) Bool() (bool, error) {
switch v := p.value.(type) {
case bool:
return v, nil
default:
return false, typeError(p, Tbool, v)
}
}
type int64er interface {
Int64() (int64, error)
}
func (p *valueProxy) Int64() (int64, error) {
switch v := p.value.(type) {
case int:
return int64(v), nil
case int32:
return int64(v), nil
case int64:
return v, nil
case float32:
return int64(v), nil
case float64:
return int64(v), nil
case int64er:
w, err := v.Int64()
if err != nil {
return 0, &errorProxy{
errorType: EconvertFailure,
parent: p,
infoStr: err.Error(),
}
}
return w, nil
default:
return 0, typeError(p, Tint64, v)
}
}
type float64er interface {
Float64() (float64, error)
}
func (p *valueProxy) Float64() (float64, error) {
switch v := p.value.(type) {
case int:
return float64(v), nil
case int32:
return float64(v), nil
case int64:
return float64(v), nil
case float32:
return float64(v), nil
case float64:
return v, nil
case float64er:
w, err := v.Float64()
if err != nil {
return 0, &errorProxy{
errorType: EconvertFailure,
parent: p,
infoStr: err.Error(),
}
}
return w, nil
default:
return 0, typeError(p, Tfloat64, v)
}
}
func (p *valueProxy) String() (string, error) {
switch v := p.value.(type) {
case string:
return v, nil
default:
return "", typeError(p, Tstring, v)
}
}
func (p *valueProxy) Array() ([]interface{}, error) {
switch v := p.value.(type) {
case []interface{}:
return v, nil
default:
return nil, typeError(p, Tarray, v)
}
}
func (p *valueProxy) Map() (map[string]interface{}, error) {
switch v := p.value.(type) {
case map[string]interface{}:
return v, nil
default:
return nil, typeError(p, Tmap, v)
}
}
func (p *valueProxy) A(n int) Proxy {
switch v := p.value.(type) {
case []interface{}:
a := "[" + strconv.Itoa(n) + "]"
if n < 0 || n >= len(v) {
return notfoundError(p, a)
}
return &valueProxy{
value: v[n],
parent: p,
label: a,
}
default:
return requiredTypeError(p, Tarray, v)
}
}
var mapType = reflect.TypeOf(map[string]interface{}(nil))
func (p *valueProxy) m(v map[string]interface{}, k string) Proxy {
a := "." + k
w, ok := v[k]
if !ok {
return notfoundError(p, a)
}
return &valueProxy{
value: w,
parent: p,
label: a,
}
}
func (p *valueProxy) M(k string) Proxy {
if v, ok := p.value.(map[string]interface{}); ok {
return p.m(v, k)
}
if rv := reflect.ValueOf(p.value); rv.IsValid() && rv.Type().ConvertibleTo(mapType) {
v, _ := rv.Convert(mapType).Interface().(map[string]interface{})
return p.m(v, k)
}
return requiredTypeError(p, Tmap, p.value)
}
func (p *valueProxy) P(q string) Proxy {
return pointer(p, q)
}
func (p *valueProxy) ProxySet() ProxySet {
switch v := p.value.(type) {
case []interface{}:
return &setProxy{
values: v,
parent: p,
}
default:
return typeError(p, Tarray, v)
}
}
func (p *valueProxy) Q(k string) ProxySet {
w := findAll(p.value, k)
return &setProxy{
values: w,
parent: p,
label: ".." + k,
}
}
func (p *valueProxy) findJPT(t string) Proxy {
switch v := p.value.(type) {
case map[string]interface{}:
return p.M(t)
case []interface{}:
n, err := strconv.ParseUint(t, 10, 0)
if err != nil {
return &errorProxy{
errorType: EinvalidIndex,
parent: p,
infoStr: err.Error(),
}
}
return p.A(int(n))
default:
return &errorProxy{
errorType: EmapNorArray,
parent: p,
actual: detectType(v),
}
}
}
func (p *valueProxy) parentFrame() frame {
return p.parent
}
func (p *valueProxy) frameLabel() string {
return p.label
}