Skip to content

Commit

Permalink
Copy kio/blockstorage/ibm to Kanister blockstorage (#4971)
Browse files Browse the repository at this point in the history
* Copy ibm from kio/blockstorage

* Update glide and imb pkg to use kanister lib
  • Loading branch information
SupriyaKasten authored and Ilya Kislenko committed Feb 18, 2019
1 parent 4245488 commit 7c7f493
Show file tree
Hide file tree
Showing 11 changed files with 826 additions and 3 deletions.
58 changes: 55 additions & 3 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import:
vcs: git
version: master
repo: https://github.com/kastenhq/stow.git
- package: github.com/IBM/ibmcloud-storage-volume-lib
version: f3805379b0af4dd418e2cdb9000f2738c15216ab
repo: https://github.com/kastenhq/ibmcloud-storage-volume-lib.git
- package: github.com/jpillora/backoff
version: 1.0.0
- package: github.com/Masterminds/sprig
Expand Down
6 changes: 6 additions & 0 deletions pkg/blockstorage/getter/getter.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package getter

import (
"context"
"github.com/pkg/errors"

"github.com/kanisterio/kanister/pkg/blockstorage"
"github.com/kanisterio/kanister/pkg/blockstorage/awsebs"
"github.com/kanisterio/kanister/pkg/blockstorage/gcepd"
"github.com/kanisterio/kanister/pkg/blockstorage/ibm"
)

// Getter is a resolver for a storage provider.
Expand All @@ -27,6 +29,8 @@ func (*getter) Get(storageType blockstorage.Type, config map[string]string) (blo
switch storageType {
case blockstorage.TypeEBS:
return awsebs.NewProvider(config)
case blockstorage.TypeSoftlayerBlock:
return ibm.NewProvider(context.TODO(), config)
case blockstorage.TypeGPD:
return gcepd.NewProvider(config)
default:
Expand All @@ -39,6 +43,8 @@ func Supported(st blockstorage.Type) bool {
switch st {
case blockstorage.TypeEBS:
return true
case blockstorage.TypeSoftlayerBlock:
return true
case blockstorage.TypeGPD:
return true
default:
Expand Down
132 changes: 132 additions & 0 deletions pkg/blockstorage/ibm/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package ibm

import (
"context"
"strings"

"github.com/BurntSushi/toml"
ibmcfg "github.com/IBM/ibmcloud-storage-volume-lib/config"
ibmprov "github.com/IBM/ibmcloud-storage-volume-lib/lib/provider"
ibmprovutils "github.com/IBM/ibmcloud-storage-volume-lib/provider/utils"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"go.uber.org/zap"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/kanisterio/kanister/pkg/kube"
)

// IBM Cloud environment variable names
const (
IBMK8sSecretName = "storage-secret-store"
IBMK8sSecretData = "slclient.toml"
IBMK8sSecretNS = "kube-system"
LibDefCfgEnv = "SECRET_CONFIG_PATH"
)

var (
blueMixCfg = ibmcfg.BluemixConfig{
IamURL: "https://iam.bluemix.net",
IamClientID: "bx",
IamClientSecret: "bx",
IamAPIKey: "free",
RefreshToken: "",
}

softLayerCfg = ibmcfg.SoftlayerConfig{
SoftlayerBlockEnabled: true,
SoftlayerBlockProviderName: "SOFTLAYER-BLOCK",
SoftlayerFileEnabled: false,
SoftlayerFileProviderName: "SOFTLAYER-FILE",
SoftlayerUsername: "",
SoftlayerAPIKey: "",
SoftlayerEndpointURL: "https://api.softlayer.com/rest/v3",
SoftlayerIMSEndpointURL: "https://api.softlayer.com/mobile/v3",
SoftlayerDataCenter: "sjc03",
SoftlayerTimeout: "20s",
SoftlayerVolProvisionTimeout: "10m",
SoftlayerRetryInterval: "5s",
}
)

//client is a wrapper for Library client
type client struct {
Service ibmprov.Session
SLCfg ibmcfg.SoftlayerConfig
}

//newClient returns a Client struct
func newClient(ctx context.Context, args map[string]string) (*client, error) {

zaplog, _ := zap.NewProduction()
defer zaplog.Sync() // nolint: errcheck

cfg, err := findDefaultConfig(ctx, args, zaplog)
if err != nil {
return nil, errors.Wrap(err, "Failed to get IBM client config")
}

provReg, err := ibmprovutils.InitProviders(cfg, zaplog)
if err != nil {
return nil, errors.Wrap(err, "Failed to Init IBM providers")
}

session, _, err := ibmprovutils.OpenProviderSession(cfg, provReg, cfg.Softlayer.SoftlayerBlockProviderName, zaplog)
if err != nil {
return nil, errors.Wrapf(err, "Failed to create Open session for IBM provider. %s", cfg.Softlayer.SoftlayerBlockProviderName)
}

return &client{
Service: session,
SLCfg: *cfg.Softlayer,
}, nil
}

func findDefaultConfig(ctx context.Context, args map[string]string, zaplog *zap.Logger) (*ibmcfg.Config, error) {
// Checking if an api key is provided via args
// If it present will use api value and default Softlayer config
if apik, ok := args[APIKeyArgName]; ok {
blueMixCfg.IamAPIKey = strings.Replace(apik, "\"", "", 2)
return &ibmcfg.Config{
Softlayer: &softLayerCfg,
Gen2: &ibmcfg.Gen2Config{},
Bluemix: &blueMixCfg,
}, nil
}
// Cheking if IBM store secret is present
ibmCfg, err := getDefIBMStoreSecret(ctx, args)
if err != nil {
log.WithError(err).Info("Could not get IBM default store secret")
} else {
return ibmCfg, nil
}
// Final attemp to get Config, by using default lib code path
defPath := ibmcfg.GetConfPath()
return ibmcfg.ReadConfig(defPath, zaplog)
}

func getDefIBMStoreSecret(ctx context.Context, args map[string]string) (*ibmcfg.Config, error) {
// Let's check if we are running in k8s and special IBM storage secret is present
k8scli, err := kube.NewClient()
if err != nil {
return nil, errors.Wrap(err, "Failed to created k8s client.")
}
secretNam := IBMK8sSecretName
secretNS := IBMK8sSecretNS

if sn, ok := args[CfgSecretNameArgName]; ok {
secretNam = sn
}

if sns, ok := args[CfgSecretNameSpaceArgName]; ok {
secretNS = sns
}

storeSecret, err := k8scli.CoreV1().Secrets(secretNS).Get(secretNam, metav1.GetOptions{})
if err != nil {
return nil, errors.Wrap(err, "Failed to read Default IBM storage secret.")
}
retConfig := ibmcfg.Config{Softlayer: &softLayerCfg}
_, err = toml.Decode(string(storeSecret.Data[IBMK8sSecretData]), &retConfig)
return &retConfig, err
}
74 changes: 74 additions & 0 deletions pkg/blockstorage/ibm/client_kube_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// +build !unit

package ibm

import (
"context"
"io/ioutil"
"os"

. "gopkg.in/check.v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"

"github.com/kanisterio/kanister/pkg/kube"
)

const (
testSecretName = "unitetestsecret"
)

type KubeTestIBMClient struct {
k8sSec *v1.Secret
k8scli kubernetes.Interface
}

var _ = Suite(&KubeTestIBMClient{})

func (s *KubeTestIBMClient) SetUpSuite(c *C) {
var secData []byte
var err error
if tomlPath, ok := os.LookupEnv(workAroundEnv); ok {
secData, err = ioutil.ReadFile(tomlPath)
c.Assert(err, IsNil)
} else {
c.Skip(workAroundEnv + " TOML path is not present")
}

secretData := make(map[string][]byte)
secretData[IBMK8sSecretData] = secData

s.k8scli, err = kube.NewClient()
c.Assert(err, IsNil)
k8sSec := v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: testSecretName,
},
Type: v1.SecretTypeOpaque,
Data: secretData,
}
s.k8sSec, err = s.k8scli.CoreV1().Secrets(IBMK8sSecretNS).Create(&k8sSec)
c.Assert(err, IsNil)
}

func (s KubeTestIBMClient) TearDownSuite(c *C) {
if _, ok := os.LookupEnv(workAroundEnv); !ok {
c.Skip(workAroundEnv + "TOML path is not present")
}
err := s.k8scli.CoreV1().Secrets(s.k8sSec.Namespace).Delete(s.k8sSec.Name, &metav1.DeleteOptions{})
c.Assert(err, IsNil)
}

func (s KubeTestIBMClient) TestIBMSecret(c *C) {
apiKey := os.Getenv(IBMApiKeyEnv)
os.Unsetenv(IBMApiKeyEnv)
defer os.Setenv(IBMApiKeyEnv, apiKey)
ibmCli, err := newClient(context.Background(), map[string]string{CfgSecretNameArgName: testSecretName})
defer ibmCli.Service.Close()
c.Assert(err, IsNil)
c.Assert(ibmCli.Service, NotNil)
c.Assert(*ibmCli, FitsTypeOf, client{})
_, err = ibmCli.Service.SnapshotsList()
c.Assert(err, IsNil)
}
Loading

0 comments on commit 7c7f493

Please sign in to comment.