[hyper-provider] 1.add doc 2.support read hyper config file
This commit is contained in:
124
providers/hypersh/README.md
Normal file
124
providers/hypersh/README.md
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
hyper.sh provider for virtual-kubelet
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
# Configure for hyper.sh
|
||||||
|
|
||||||
|
## Use environment variable
|
||||||
|
|
||||||
|
- necessary
|
||||||
|
- HYPER_ACCESS_KEY
|
||||||
|
- HYPER_SECRET_KEY
|
||||||
|
- optional
|
||||||
|
- HYPER_INSTANCE_TYPE: default s4
|
||||||
|
- HYPER_DEFAULT_REGION: default us-west-1
|
||||||
|
- HYPER_HOST: tcp://${HYPER_DEFAULT_REGION}.hyper.sh:443
|
||||||
|
|
||||||
|
> You can use You can use either HYPER_HOST or HYPER_DEFAULT_REGION
|
||||||
|
|
||||||
|
|
||||||
|
## Use config file
|
||||||
|
|
||||||
|
> default config file for hyper.sh is ~/.hyper/config.json
|
||||||
|
|
||||||
|
```
|
||||||
|
//example configuration file for Hyper.sh
|
||||||
|
{
|
||||||
|
"auths": {
|
||||||
|
"https://index.docker.io/v1/": {
|
||||||
|
"auth": "xxxxxx",
|
||||||
|
"email": "xxxxxx"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"clouds": {
|
||||||
|
"tcp://*.hyper.sh:443": {
|
||||||
|
"accesskey": "xxxxxx",
|
||||||
|
"secretkey": "xxxxxx",
|
||||||
|
"region": "us-west-1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Usage of virtual-kubelet cli
|
||||||
|
|
||||||
|
```
|
||||||
|
// example 1 : use environment variable
|
||||||
|
export HYPER_ACCESS_KEY=xxxxxx
|
||||||
|
export HYPER_SECRET_KEY=xxxxxx
|
||||||
|
export HYPER_DEFAULT_REGION=eu-central-1
|
||||||
|
export HYPER_INSTANCE_TYPE=s4
|
||||||
|
./virtual-kubelet --provider=hyper
|
||||||
|
|
||||||
|
|
||||||
|
// example 2 : use default config file(~/.hyper/config.json)
|
||||||
|
unset HYPER_ACCESS_KEY
|
||||||
|
unset HYPER_SECRET_KEY
|
||||||
|
export HYPER_DEFAULT_REGION=eu-central-1
|
||||||
|
./virtual-kubelet --provider=hyper
|
||||||
|
|
||||||
|
|
||||||
|
// example 3 : use custom config file, eg: ~/.hyper2/config.json
|
||||||
|
$ ./virtual-kubelet --provider=hyper --provider-config=$HOME/.hyper2
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# Quick Start
|
||||||
|
|
||||||
|
## create pod yaml
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cat pod-nginx
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: nginx
|
||||||
|
spec:
|
||||||
|
nodeName: virtual-kubelet
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx:latest
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
```
|
||||||
|
|
||||||
|
## create pod
|
||||||
|
|
||||||
|
```
|
||||||
|
$ kubectl create -f pod-nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
## list container on hyper.sh
|
||||||
|
|
||||||
|
```
|
||||||
|
$ hyper ps
|
||||||
|
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES PUBLIC IP
|
||||||
|
a0ae3d4112d5 nginx:latest "nginx -g 'daemon off" 9 seconds ago Up 4 seconds 0.0.0.0:80->80/tcp pod-nginx-nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
## server log
|
||||||
|
|
||||||
|
```
|
||||||
|
$ export HYPER_DEFAULT_REGION=eu-central-1
|
||||||
|
$ ./virtual-kubelet --provider=hyper --provider-config=$HOME/.hyper3
|
||||||
|
/home/xjimmy/.kube/config
|
||||||
|
2017/12/20 17:30:30 config file under "/home/xjimmy/.hyper3" was loaded
|
||||||
|
2017/12/20 17:30:30
|
||||||
|
Host: tcp://eu-central-1.hyper.sh:443
|
||||||
|
AccessKey: K**********
|
||||||
|
SecretKey: 4**********
|
||||||
|
InstanceType: s4
|
||||||
|
2017/12/20 17:30:31 Node 'virtual-kubelet' with OS type 'Linux' registered
|
||||||
|
2017/12/20 17:30:31 receive GetPods
|
||||||
|
2017/12/20 17:30:32 found 0 pods
|
||||||
|
2017/12/20 17:30:37 receive GetPods
|
||||||
|
2017/12/20 17:30:37 found 0 pods
|
||||||
|
2017/12/20 17:30:38 Error retrieving pod 'nginx' from provider: Error: No such container: pod-nginx-nginx
|
||||||
|
2017/12/20 17:30:38 receive CreatePod "nginx"
|
||||||
|
2017/12/20 17:30:38 container "a0ae3d4112d53023b5972906f2f15c0d34360c132b3c273b286473afad613b63" for pod "nginx" was created
|
||||||
|
2017/12/20 17:30:43 container "a0ae3d4112d53023b5972906f2f15c0d34360c132b3c273b286473afad613b63" for pod "nginx" was started
|
||||||
|
2017/12/20 17:30:43 Pod 'nginx' created.
|
||||||
|
2017/12/20 17:30:43 receive GetPods
|
||||||
|
2017/12/20 17:30:43 found 1 pods
|
||||||
|
2017/12/20 17:30:47 receive GetPods
|
||||||
|
2017/12/20 17:30:47 found 1 pods
|
||||||
|
```
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
package hypersh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
|
||||||
"github.com/virtual-kubelet/virtual-kubelet/providers"
|
|
||||||
)
|
|
||||||
|
|
||||||
type providerConfig struct {
|
|
||||||
Region string
|
|
||||||
AccessKey string
|
|
||||||
SecretKey string
|
|
||||||
OperatingSystem string
|
|
||||||
CPU string
|
|
||||||
Memory string
|
|
||||||
InstanceType string
|
|
||||||
Pods string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *HyperProvider) loadConfig(r io.Reader) error {
|
|
||||||
var config providerConfig
|
|
||||||
if _, err := toml.DecodeReader(r, &config); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
p.region = config.Region
|
|
||||||
p.accessKey = config.AccessKey
|
|
||||||
p.secretKey = config.SecretKey
|
|
||||||
|
|
||||||
p.instanceType = "s4"
|
|
||||||
if config.InstanceType != "" {
|
|
||||||
p.instanceType = config.InstanceType
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default to 20 mcpu
|
|
||||||
p.cpu = "20"
|
|
||||||
if config.CPU != "" {
|
|
||||||
p.cpu = config.CPU
|
|
||||||
}
|
|
||||||
// Default to 100Gi
|
|
||||||
p.memory = "100Gi"
|
|
||||||
if config.Memory != "" {
|
|
||||||
p.memory = config.Memory
|
|
||||||
}
|
|
||||||
// Default to 20 pods
|
|
||||||
p.pods = "20"
|
|
||||||
if config.Pods != "" {
|
|
||||||
p.pods = config.Pods
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default to Linux if the operating system was not defined in the config.
|
|
||||||
if config.OperatingSystem == "" {
|
|
||||||
config.OperatingSystem = providers.OperatingSystemLinux
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate operating system from config.
|
|
||||||
if config.OperatingSystem != providers.OperatingSystemLinux {
|
|
||||||
return fmt.Errorf("%q is not a valid operating system, only %s is valid", config.OperatingSystem, providers.OperatingSystemLinux)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.operatingSystem = config.OperatingSystem
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# example configuration file for Hyper.sh virtual-kubelet
|
|
||||||
|
|
||||||
AccessKey = ""
|
|
||||||
SecretKey = ""
|
|
||||||
Region = "us-west-1"
|
|
||||||
CPU = 100
|
|
||||||
Memory = 100Gi
|
|
||||||
Pods = 50
|
|
||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -18,6 +19,8 @@ import (
|
|||||||
"github.com/hyperhq/hyper-api/types/container"
|
"github.com/hyperhq/hyper-api/types/container"
|
||||||
"github.com/hyperhq/hyper-api/types/filters"
|
"github.com/hyperhq/hyper-api/types/filters"
|
||||||
"github.com/hyperhq/hyper-api/types/network"
|
"github.com/hyperhq/hyper-api/types/network"
|
||||||
|
"github.com/hyperhq/hypercli/cliconfig"
|
||||||
|
"github.com/hyperhq/hypercli/opts"
|
||||||
"github.com/virtual-kubelet/virtual-kubelet/manager"
|
"github.com/virtual-kubelet/virtual-kubelet/manager"
|
||||||
"github.com/virtual-kubelet/virtual-kubelet/providers"
|
"github.com/virtual-kubelet/virtual-kubelet/providers"
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
@@ -37,10 +40,12 @@ const (
|
|||||||
// HyperProvider implements the virtual-kubelet provider interface and communicates with hyper.sh APIs.
|
// HyperProvider implements the virtual-kubelet provider interface and communicates with hyper.sh APIs.
|
||||||
type HyperProvider struct {
|
type HyperProvider struct {
|
||||||
hyperClient *hyper.Client
|
hyperClient *hyper.Client
|
||||||
|
configFile *cliconfig.ConfigFile
|
||||||
resourceManager *manager.ResourceManager
|
resourceManager *manager.ResourceManager
|
||||||
nodeName string
|
nodeName string
|
||||||
operatingSystem string
|
operatingSystem string
|
||||||
region string
|
region string
|
||||||
|
host string
|
||||||
accessKey string
|
accessKey string
|
||||||
secretKey string
|
secretKey string
|
||||||
cpu string
|
cpu string
|
||||||
@@ -51,41 +56,102 @@ type HyperProvider struct {
|
|||||||
|
|
||||||
// NewHyperProvider creates a new HyperProvider
|
// NewHyperProvider creates a new HyperProvider
|
||||||
func NewHyperProvider(config string, rm *manager.ResourceManager, nodeName, operatingSystem string) (*HyperProvider, error) {
|
func NewHyperProvider(config string, rm *manager.ResourceManager, nodeName, operatingSystem string) (*HyperProvider, error) {
|
||||||
var p HyperProvider
|
var (
|
||||||
var err error
|
p HyperProvider
|
||||||
|
err error
|
||||||
|
host string
|
||||||
|
dft bool
|
||||||
|
tlsOptions = &tlsconfig.Options{InsecureSkipVerify: false}
|
||||||
|
)
|
||||||
|
|
||||||
p.resourceManager = rm
|
p.resourceManager = rm
|
||||||
|
|
||||||
if config != "" {
|
// Get config from environment variable
|
||||||
f, err := os.Open(config)
|
if h := os.Getenv("HYPER_HOST"); h != "" {
|
||||||
if err != nil {
|
p.host = h
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
if err := p.loadConfig(f); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if ak := os.Getenv("HYPER_ACCESS_KEY"); ak != "" {
|
||||||
if ak := os.Getenv("HYPERSH_ACCESS_KEY"); ak != "" {
|
|
||||||
p.accessKey = ak
|
p.accessKey = ak
|
||||||
}
|
}
|
||||||
|
if sk := os.Getenv("HYPER_SECRET_KEY"); sk != "" {
|
||||||
if sk := os.Getenv("HYPERSH_SECRET_KEY"); sk != "" {
|
|
||||||
p.secretKey = sk
|
p.secretKey = sk
|
||||||
}
|
}
|
||||||
|
if p.host == "" {
|
||||||
if r := os.Getenv("HYPERSH_REGION"); r != "" {
|
// ignore HYPER_DEFAULT_REGION when HYPER_HOST was specified
|
||||||
p.region = r
|
if r := os.Getenv("HYPER_DEFAULT_REGION"); r != "" {
|
||||||
|
p.region = r
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if it := os.Getenv("HYPER_INSTANCE_TYPE"); it != "" {
|
||||||
if it := os.Getenv("HYPERSH_INSTANCE_TYPE"); it != "" {
|
|
||||||
p.instanceType = it
|
p.instanceType = it
|
||||||
|
} else {
|
||||||
|
p.instanceType = "s4"
|
||||||
}
|
}
|
||||||
|
|
||||||
host = fmt.Sprintf("tcp://%s.hyper.sh:443", p.region)
|
if p.accessKey != "" || p.secretKey != "" {
|
||||||
httpClient, err := newHTTPClient(host, &tlsconfig.Options{InsecureSkipVerify: false})
|
//use environment variable
|
||||||
|
if p.accessKey == "" || p.secretKey == "" {
|
||||||
|
return nil, fmt.Errorf("WARNING: Need to specify HYPER_ACCESS_KEY and HYPER_SECRET_KEY at the same time.")
|
||||||
|
}
|
||||||
|
log.Printf("Use AccessKey and SecretKey from HYPER_ACCESS_KEY and HYPER_SECRET_KEY")
|
||||||
|
if p.region == "" {
|
||||||
|
p.region = cliconfig.DefaultHyperRegion
|
||||||
|
}
|
||||||
|
if p.host == "" {
|
||||||
|
host, _, err = p.getServerHost(p.region, tlsOptions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p.host = host
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// use config file, default path is ~/.hyper
|
||||||
|
if config == "" {
|
||||||
|
config = cliconfig.ConfigDir()
|
||||||
|
}
|
||||||
|
configFile, err := cliconfig.Load(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("WARNING: Error loading config file %q: %v\n", config, err)
|
||||||
|
}
|
||||||
|
p.configFile = configFile
|
||||||
|
log.Printf("config file under %q was loaded\n", config)
|
||||||
|
|
||||||
|
if p.host == "" {
|
||||||
|
host, dft, err = p.getServerHost(p.region, tlsOptions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p.host = host
|
||||||
|
}
|
||||||
|
// Get Region, AccessKey and SecretKey from config file
|
||||||
|
cc, ok := configFile.CloudConfig[p.host]
|
||||||
|
if !ok {
|
||||||
|
cc, ok = configFile.CloudConfig[cliconfig.DefaultHyperFormat]
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
p.accessKey = cc.AccessKey
|
||||||
|
p.secretKey = cc.SecretKey
|
||||||
|
|
||||||
|
if p.region == "" && dft {
|
||||||
|
if p.region = cc.Region; p.region == "" {
|
||||||
|
p.region = p.getDefaultRegion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !dft {
|
||||||
|
if p.region = cc.Region; p.region == "" {
|
||||||
|
p.region = cliconfig.DefaultHyperRegion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("WARNING: can not find entrypoint %q in config file", cliconfig.DefaultHyperFormat)
|
||||||
|
}
|
||||||
|
if p.accessKey == "" || p.secretKey == "" {
|
||||||
|
return nil, fmt.Errorf("WARNING: AccessKey or SecretKey is empty in config %q", config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("\n Host: %s\n AccessKey: %s**********\n SecretKey: %s**********\n InstanceType: %s\n", p.host, p.accessKey[0:1], p.secretKey[0:1], p.instanceType)
|
||||||
|
httpClient, err := newHTTPClient(p.host, tlsOptions)
|
||||||
|
|
||||||
customHeaders := map[string]string{}
|
customHeaders := map[string]string{}
|
||||||
ver := "0.1"
|
ver := "0.1"
|
||||||
@@ -94,11 +160,15 @@ func NewHyperProvider(config string, rm *manager.ResourceManager, nodeName, oper
|
|||||||
p.operatingSystem = operatingSystem
|
p.operatingSystem = operatingSystem
|
||||||
p.nodeName = nodeName
|
p.nodeName = nodeName
|
||||||
|
|
||||||
p.hyperClient, err = hyper.NewClient(host, verStr, httpClient, customHeaders, p.accessKey, p.secretKey, p.region)
|
p.hyperClient, err = hyper.NewClient(p.host, verStr, httpClient, customHeaders, p.accessKey, p.secretKey, p.region)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//test connect to hyper.sh
|
||||||
|
_, err = p.hyperClient.Info(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &p, nil
|
return &p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +271,7 @@ func (p *HyperProvider) DeletePod(pod *v1.Pod) (err error) {
|
|||||||
if v, ok := container.Config.Labels[containerLabel]; ok {
|
if v, ok := container.Config.Labels[containerLabel]; ok {
|
||||||
// Check value of label
|
// Check value of label
|
||||||
if v != pod.Name {
|
if v != pod.Name {
|
||||||
return fmt.Errorf("the label %q of hyper container %q should be %q, but it's %q currently", pod.Name, containerLabel, container.Name, pod.Name, v)
|
return fmt.Errorf("the label %q of hyper container %q should be %q, but it's %q currently", containerLabel, container.Name, pod.Name, v)
|
||||||
}
|
}
|
||||||
rmOptions := types.ContainerRemoveOptions{
|
rmOptions := types.ContainerRemoveOptions{
|
||||||
RemoveVolumes: true,
|
RemoveVolumes: true,
|
||||||
@@ -218,7 +288,7 @@ func (p *HyperProvider) DeletePod(pod *v1.Pod) (err error) {
|
|||||||
}
|
}
|
||||||
log.Printf("container %q for pod %q was deleted\n", container.ID, pod.Name)
|
log.Printf("container %q for pod %q was deleted\n", container.ID, pod.Name)
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("hyper container %q has no label %q", pod.Name, container.Name, containerLabel)
|
return fmt.Errorf("hyper container %q has no label %q", container.Name, containerLabel)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -275,7 +345,7 @@ func (p *HyperProvider) GetPods() ([]*v1.Pod, error) {
|
|||||||
for _, container := range containers {
|
for _, container := range containers {
|
||||||
pod, err := containerToPod(&container)
|
pod, err := containerToPod(&container)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("convert container %q to pod error: %v\n", container.ID, err)
|
log.Printf("WARNING: convert container %q to pod error: %v\n", container.ID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pods = append(pods, pod)
|
pods = append(pods, pod)
|
||||||
@@ -541,3 +611,26 @@ func hyperStateToPodPhase(state string) v1.PodPhase {
|
|||||||
}
|
}
|
||||||
return v1.PodUnknown
|
return v1.PodUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *HyperProvider) getServerHost(region string, tlsOptions *tlsconfig.Options) (host string, dft bool, err error) {
|
||||||
|
dft = false
|
||||||
|
host = region
|
||||||
|
if host == "" {
|
||||||
|
host = os.Getenv("HYPER_DEFAULT_REGION")
|
||||||
|
region = p.getDefaultRegion()
|
||||||
|
}
|
||||||
|
if _, err := url.ParseRequestURI(host); err != nil {
|
||||||
|
host = "tcp://" + region + "." + cliconfig.DefaultHyperEndpoint
|
||||||
|
dft = true
|
||||||
|
}
|
||||||
|
host, err = opts.ParseHost(tlsOptions != nil, host)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *HyperProvider) getDefaultRegion() string {
|
||||||
|
cc, ok := p.configFile.CloudConfig[cliconfig.DefaultHyperFormat]
|
||||||
|
if ok && cc.Region != "" {
|
||||||
|
return cc.Region
|
||||||
|
}
|
||||||
|
return cliconfig.DefaultHyperRegion
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user