Skip to content

Commit

Permalink
Merge pull request #35 from maleck13/AEROGEAR-1865-provision-identity…
Browse files Browse the repository at this point in the history
…-service

Aerogear 1865 provision identity service
  • Loading branch information
maleck13 authored Jan 17, 2018
2 parents 147da7c + 29bb01b commit 6bea926
Show file tree
Hide file tree
Showing 5 changed files with 308 additions and 49 deletions.
6 changes: 6 additions & 0 deletions cmd/mobile/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (

"path/filepath"

"log"

m "github.com/aerogear/mobile-cli/pkg/client/mobile/clientset/versioned"
sc "github.com/aerogear/mobile-cli/pkg/client/servicecatalog/clientset/versioned"
"github.com/aerogear/mobile-cli/pkg/cmd"
Expand Down Expand Up @@ -98,6 +100,10 @@ func main() {
}

if err := rootCmd.Execute(); err != nil {
// as using pkg/errors lets allow the full stack to be seen if needed
if os.Getenv("MCP_DEBUG") == "true" {
log.Fatalf("error: %+v", err)
}
os.Exit(1)
}
}
Expand Down
1 change: 0 additions & 1 deletion pkg/cmd/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ func (cc *ClientCmd) GetClientCmd() *cobra.Command {
kubectl plugin mobile get client <clientID>
oc plugin mobile get client <clientID>`,
RunE: func(cmd *cobra.Command, args []string) error {
fmt.Println(args, len(args))
if len(args) != 1 {
return errors.New("missing argument <clientID>")
}
Expand Down
146 changes: 98 additions & 48 deletions pkg/cmd/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func (sc *ServicesCmd) ListServicesCmd() *cobra.Command {
return err
}

params := &instanceCreateParams{}
params := &InstanceCreateParams{}
if err := json.Unmarshal(clusterServicePlan.Spec.ServiceInstanceCreateParameterSchema.Raw, &params); err != nil {
return err
}
Expand All @@ -106,11 +106,11 @@ func (sc *ServicesCmd) ListServicesCmd() *cobra.Command {
integrations = v
}

data = append(data, []string{item.Spec.ExternalName, serviceName, integrations, strings.Join(createParams, ",\n"), item.Name})
data = append(data, []string{serviceName, integrations, strings.Join(createParams, ",\n")})
}
table := tablewriter.NewWriter(writer)
table.AppendBulk(data)
table.SetHeader([]string{"ID", "Name", "Integrations", "Parameters", "Class"})
table.SetHeader([]string{"Name", "Integrations", "Parameters"})
table.Render()
return nil
})
Expand All @@ -124,7 +124,7 @@ func findServiceClassByName(scClient versioned.Interface, name string) (*v1beta1
return nil, err
}
if mobileServices == nil || len(mobileServices.Items) == 0 {
return nil, errors.New("failed to find and service classes for " + name)
return nil, errors.New("failed to find serviceclass with name: " + name)
}

for _, item := range mobileServices.Items {
Expand All @@ -137,11 +137,12 @@ func findServiceClassByName(scClient versioned.Interface, name string) (*v1beta1
return &item, nil
}
}
return nil, nil
return nil, errors.New("failed to find serviceclass with name: " + name)

}

func findServicePlanByNameAndClass(scClient versioned.Interface, planName, serviceClassName string) (*v1beta1.ClusterServicePlan, error) {

plans, err := scClient.ServicecatalogV1beta1().ClusterServicePlans().List(metav1.ListOptions{})
if err != nil {
return nil, err
Expand All @@ -152,10 +153,31 @@ func findServicePlanByNameAndClass(scClient versioned.Interface, planName, servi
}
}

return nil, nil
return nil, errors.New("failed to find serviceplan associated with the serviceclass " + serviceClassName)
}

func requiredParam(instParams InstanceCreateParams, key string) bool {
for _, r := range instParams.Required {
if r == key {
return true
}
}
return false
}

func parseParams(keyVals []string) (map[string]string, error) {
params := map[string]string{}
for _, p := range keyVals {
kv := strings.Split(p, "=")
if len(kv) != 2 {
return nil, NewIncorrectParameterFormat("key value pairs are needed failed to find one: " + p)
}
params[strings.TrimSpace(kv[0])] = kv[1]
}
return params, nil
}

type instanceCreateParams struct {
type InstanceCreateParams struct {
AdditionalProperties bool `json:"additionalProperties"`
Properties map[string]map[string]interface{} `json:"properties"`
Required []string `json:"required"`
Expand All @@ -166,10 +188,16 @@ func (sc *ServicesCmd) CreateServiceInstanceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "serviceinstance <serviceName>",
Short: `create a running instance of the given service`,
Long: `Create service instance, allows you to create a running instance of a service in your namespace.
To see which services are available, first list them using the "mobile get services" command from this tool.
Once you have selected a service, take note of its name then run:
create serviceinstance <selectedServiceName>`,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return errors.New("expected the name of a service to provision")
}
// find our serviceclass and plan
serviceName := args[0]

ns, err := currentNamespace(cmd.Flags())
Expand All @@ -178,47 +206,66 @@ func (sc *ServicesCmd) CreateServiceInstanceCmd() *cobra.Command {
}

clusterServiceClass, err := findServiceClassByName(sc.scClient, serviceName)
if err != nil || clusterServiceClass == nil {
msg := "failed to find a service class associated with that name "
if err != nil {
msg += err.Error()
}
return errors.New(msg)
if err != nil {
return errors.WithStack(err)
}
clusterServicePlan, err := findServicePlanByNameAndClass(sc.scClient, "default", clusterServiceClass.Name)
if err != nil {
return err
return errors.WithStack(err)
}

if clusterServicePlan == nil {
return errors.New("failed to find service plan with name default for service " + serviceName)
// handle the params
params, err := cmd.Flags().GetStringArray("params")
if err != nil {
return errors.WithStack(err)
}

params := &instanceCreateParams{}

if err := json.Unmarshal(clusterServicePlan.Spec.ServiceInstanceCreateParameterSchema.Raw, params); err != nil {
return err
parsedParams, err := parseParams(params)
if err != nil {
return errors.WithStack(err)
}
instParams := &InstanceCreateParams{}
if err := json.Unmarshal(clusterServicePlan.Spec.ServiceInstanceCreateParameterSchema.Raw, instParams); err != nil {
return errors.WithStack(err)
}
scanner := bufio.NewScanner(os.Stdin)
for k, v := range params.Properties {
fmt.Printf("Set value for %v, default value: %v", k, v["default"])
scanner.Scan()
//
val := scanner.Text()
if val == "" {
val = v["default"].(string)

if len(parsedParams) > 0 {
for k, v := range instParams.Properties {
defaultVal := v["default"]
if pVal, ok := parsedParams[k]; !ok && requiredParam(*instParams, k) || requiredParam(*instParams, k) && pVal == "" {
if defaultVal != nil {
//use default
v["value"] = defaultVal
continue
}
return errors.New(fmt.Sprintf("missing required parameter %s", k))
}
v["value"] = parsedParams[k]
instParams.Properties[k] = v
}
} else {

scanner := bufio.NewScanner(os.Stdin)
for k, v := range instParams.Properties {
questionFormat := "Set value for %s [default value: %s required: %v]"

fmt.Println(fmt.Sprintf(questionFormat, k, v["default"], requiredParam(*instParams, k)))
scanner.Scan()
//
val := scanner.Text()
if val == "" {
val = v["default"].(string)
}
v["value"] = val
instParams.Properties[k] = v
fmt.Println("set value for " + k + " to : " + val)
}
v["value"] = val
params.Properties[k] = v
fmt.Println("set value for " + k + " to : " + val)
}

validServiceName := clusterServiceClass.Spec.ExternalName
sid := uuid.NewV4().String()
extMeta := clusterServiceClass.Spec.ExternalMetadata.Raw
var extServiceClass ExternalServiceMetaData
if err := json.Unmarshal(extMeta, &extServiceClass); err != nil {
return err
return errors.WithStack(err)
}

si := v1beta1.ServiceInstance{
Expand Down Expand Up @@ -251,7 +298,7 @@ func (sc *ServicesCmd) CreateServiceInstanceCmd() *cobra.Command {
},
}
if _, err := sc.scClient.ServicecatalogV1beta1().ServiceInstances(ns).Create(&si); err != nil {
return err
return errors.WithStack(err)
}

pSecret := v1.Secret{
Expand All @@ -262,38 +309,40 @@ func (sc *ServicesCmd) CreateServiceInstanceCmd() *cobra.Command {
pSecret.Data = map[string][]byte{}
parameters := map[string]string{}

for k, v := range params.Properties {
parameters[k] = v["value"].(string)
for k, v := range instParams.Properties {
if v, ok := v["value"]; ok && v != nil {
parameters[k] = v.(string)
}
}
secretData, err := json.Marshal(parameters)
if err != nil {
return err
return errors.WithStack(err)
}
pSecret.Data["parameters"] = secretData
if _, err := sc.k8Client.CoreV1().Secrets(ns).Create(&pSecret); err != nil {
return err
return errors.WithStack(err)
}

noWait, err := cmd.PersistentFlags().GetBool("no-wait")
if err != nil {
return err
return errors.WithStack(err)
}
if noWait {
return nil
}
w, err := sc.scClient.ServicecatalogV1beta1().ServiceInstances(ns).Watch(metav1.ListOptions{LabelSelector: "id=" + sid})
if err != nil {
return err
return errors.WithStack(err)
}
for u := range w.ResultChan() {
o := u.Object.(*v1beta1.ServiceInstance)
switch u.Type {
case watch.Error:
w.Stop()
return errors.New("unexpected error watching ServiceInstance " + err.Error())
case watch.Modified:
o := u.Object.(*v1beta1.ServiceInstance)
lastOp := o.Status.LastOperation
if nil != lastOp {
//fmt.Println("last operation " + *lastOp)
}
for _, c := range o.Status.Conditions {
fmt.Println(c.Message)
fmt.Println("status: " + c.Message)
if c.Type == "Ready" && c.Status == "True" {
w.Stop()
}
Expand All @@ -304,7 +353,8 @@ func (sc *ServicesCmd) CreateServiceInstanceCmd() *cobra.Command {
return nil
},
}
cmd.PersistentFlags().Bool("no-wait", false, "--no-wait will cause the command to exit immediately instead of waiting for the service to be provisioned")
cmd.PersistentFlags().Bool("no-wait", false, "--no-wait will cause the command to exit immediately after a successful response instead of waiting until the service is fully provisioned")
cmd.PersistentFlags().StringArrayP("params", "p", []string{}, "set the parameters needed to set up the service programatically rather than being prompted for them: -p PARAM1=val -p PARAM2=val2")
return cmd
}

Expand Down
Loading

0 comments on commit 6bea926

Please sign in to comment.