Skip to content

Commit

Permalink
kyma provision
Browse files Browse the repository at this point in the history
  • Loading branch information
halamix2 committed Feb 28, 2024
1 parent c4fb953 commit 0fe1273
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 6 deletions.
Binary file added __debug_bin678796628
Binary file not shown.
87 changes: 87 additions & 0 deletions internal/btp/provision.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package btp

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)

const provisionEndpoint = "provisioning/v1/environments"

type ProvisionEnvironment struct {
// Description string `json:"description,omitempty"`
EnvironmentType string `json:"environmentType"`
// LandscapeLabel string `json:"landscapeLabel,omitempty"`
Name string `json:"name"`
// Origin string `json:"origin,omitempty"`
Parameters KymaParameters `json:"parameters"`
PlanName string `json:"planName"`
// ServiceName string `json:"serviceName,omitempty"`
// TechnicalKey string `json:"technicalKey,omitempty"`
User string `json:"user"`
}

type KymaParameters struct {
Name string `json:"name"`
Region string `json:"region"`
}

type ProvisionResponse struct {
ID string `json:"id"`
Name string `json:"name"`
BrokerID string `json:"brokerId"`
GlobalAccountGUID string `json:"globalAccountGUID"`
SubaccountGUID string `json:"subaccountGUID"`
TenantID string `json:"tenantId"`
ServiceID string `json:"serviceId"`
PlanID string `json:"planId"`
DashboardURL string `json:"dashboardUrl"`
Operation string `json:"operation"`
Parameters string `json:"parameters"`
Labels string `json:"labels"`
// CustomLabels struct {} `json:"customLabels"`
Type string `json:"type"`
Status string `json:"status"`
EnvironmentType string `json:"environmentType"`
PlatformID string `json:"platformId"`
CreatedDate int64 `json:"createdDate"`
ModifiedDate int64 `json:"modifiedDate"`
State string `json:"state"`
StateMessage string `json:"stateMessage"`
ServiceName string `json:"serviceName"`
PlanName string `json:"planName"`
}

func (c *LocalClient) Provision(pe *ProvisionEnvironment) (*ProvisionResponse, error) {
reqData, err := json.Marshal(pe)
if err != nil {
return nil, err
}

provisionURL := fmt.Sprintf("%s/%s", c.credentials.Endpoints.ProvisioningServiceURL, provisionEndpoint)
options := requestOptions{
Body: bytes.NewBuffer(reqData),
Headers: map[string]string{
"Content-Type": "application/json",
},
}

response, err := c.cis.post(provisionURL, options)
if err != nil {
return nil, fmt.Errorf("failed to provision: %s", err.Error())
}
defer response.Body.Close()

return decodeProvisionSuccessResponse(response)
}

func decodeProvisionSuccessResponse(response *http.Response) (*ProvisionResponse, error) {
provisionResponse := ProvisionResponse{}
err := json.NewDecoder(response.Body).Decode(&provisionResponse)
if err != nil {
return nil, fmt.Errorf("failed to decode response: %s", err.Error())
}

return &provisionResponse, nil
}
142 changes: 142 additions & 0 deletions internal/btp/provision_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package btp

import (
"encoding/json"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"testing"

"github.com/stretchr/testify/require"
)

func fixProvisionHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != fmt.Sprintf("/%s", provisionEndpoint) {
w.WriteHeader(404)
return
}
request := ProvisionEnvironment{}
err := json.NewDecoder(r.Body).Decode(&request)
require.NoError(t, err)

resp := ProvisionResponse{
Name: request.Name,
}

data, err := json.Marshal(resp)
require.NoError(t, err)

w.WriteHeader(202)
_, err = w.Write(data)
require.NoError(t, err)
}
}

func fixProvisionErrorHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, _ *http.Request) {
data := cisErrorResponse{
Error: cisError{
Message: "error",
},
}
response, err := json.Marshal(data)
require.NoError(t, err)

w.WriteHeader(401)
_, err = w.Write(response)
require.NoError(t, err)
}
}

func TestCISClient_Provision(t *testing.T) {
t.Parallel()

svrGood := httptest.NewServer(http.HandlerFunc(fixProvisionHandler(t)))
defer svrGood.Close()
svrBad := httptest.NewServer(http.HandlerFunc(fixProvisionErrorHandler(t)))
defer svrBad.Close()

tests := []struct {
name string
credentials *CISCredentials
token *XSUAAToken
pe *ProvisionEnvironment
wantedResponse *ProvisionResponse
expectedErr error
}{
{
name: "Correct data",
credentials: &CISCredentials{
Endpoints: Endpoints{
ProvisioningServiceURL: svrGood.URL,
},
},
token: &XSUAAToken{},
pe: &ProvisionEnvironment{
Name: "name",
},
wantedResponse: &ProvisionResponse{
Name: "name",
},
expectedErr: nil,
},
{
name: "Incorrect URL",
credentials: &CISCredentials{
Endpoints: Endpoints{
ProvisioningServiceURL: "?\n?",
},
},
token: &XSUAAToken{},
pe: &ProvisionEnvironment{
Name: "name",
},
wantedResponse: nil,
expectedErr: errors.New("failed to provision: failed to build request: parse \"?\\n?/provisioning/v1/environments\": net/url: invalid control character in URL"),
},
{
name: "Wrong URL",
credentials: &CISCredentials{
Endpoints: Endpoints{
ProvisioningServiceURL: "http://doesnotexist",
},
},
token: &XSUAAToken{},
pe: &ProvisionEnvironment{
Name: "name",
},
wantedResponse: nil,
expectedErr: errors.New("failed to provision: failed to get data from server: Post \"http://doesnotexist/provisioning/v1/environments\": dial tcp: lookup doesnotexist: no such host"),
},
{
name: "Error response",
credentials: &CISCredentials{
Endpoints: Endpoints{
ProvisioningServiceURL: svrBad.URL,
},
},
token: &XSUAAToken{},
pe: &ProvisionEnvironment{
Name: "name",
},
wantedResponse: nil,
expectedErr: errors.New("failed to provision: error"),
},
}
for _, tt := range tests {
pe := tt.pe
credentials := tt.credentials
token := tt.token
wantedResponse := tt.wantedResponse
expectedErr := tt.expectedErr
t.Run(tt.name, func(t *testing.T) {
c := NewLocalClient(credentials, token)

response, err := c.Provision(pe)
require.Equal(t, expectedErr, err)
require.Equal(t, wantedResponse, response)
})
}
}
35 changes: 29 additions & 6 deletions internal/cmd/provision/provision.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package provision

import (
"encoding/json"
"fmt"

"github.com/kyma-project/cli.v3/internal/btp"
Expand All @@ -10,20 +9,33 @@ import (

type provisionConfig struct {
credentialsPath string
plan string
environmentName string
clusterName string
region string
}

func NewProvisionCMD() *cobra.Command {
config := provisionConfig{}

cmd := &cobra.Command{
Use: "provision",
Use: "provision",
Short: "Provisions a Kyma cluster on the BTP.",
Long: `Use this command to provision a Kyma environment on the SAP BTP platform.
`,
RunE: func(_ *cobra.Command, _ []string) error {
return runProvision(&config)
},
}

cmd.PersistentFlags()
cmd.Flags().StringVar(&config.credentialsPath, "credentials-path", "", "Path to the CIS credentials file.")

cmd.Flags().StringVar(&config.plan, "plan", "trial", "Name of the Kyma environment plan, e.g trial, azure, aws, gcp.")
cmd.Flags().StringVar(&config.environmentName, "environment-name", "kyma", "Name of the environment in the BTP.")
cmd.Flags().StringVar(&config.clusterName, "cluster-name", "kyma", "Name of the Kyma cluster.")
cmd.Flags().StringVar(&config.region, "region", "", "Name of the region of the Kyma cluster.")

_ = cmd.MarkFlagRequired("credentials-path")

return cmd
Expand All @@ -40,13 +52,24 @@ func runProvision(config *provisionConfig) error {
return fmt.Errorf("failed to get access token: %s", err.Error())
}

// TODO: remove in next interation
data, err := json.Marshal(token)
localCISClient := btp.NewLocalClient(credentials, token)

ProvisionEnvironment := &btp.ProvisionEnvironment{
EnvironmentType: "kyma",
PlanName: config.plan,
Name: config.environmentName,
User: "kyma-cli",
Parameters: btp.KymaParameters{
Name: config.clusterName,
Region: config.region,
},
}
response, err := localCISClient.Provision(ProvisionEnvironment)
if err != nil {
return err
return fmt.Errorf("failed to provision kyma runtime: %s", err.Error())
}

fmt.Printf("%s\n", data)
fmt.Printf("Kyma environment provisioning, environment name: '%s', id: '%s'\n", response.Name, response.ID)

return nil
}

0 comments on commit 0fe1273

Please sign in to comment.