Skip to content

Commit

Permalink
Enable automated install of vsphere cpi/csi
Browse files Browse the repository at this point in the history
  • Loading branch information
slickwarren committed Mar 15, 2024
1 parent 9b663d9 commit b5ca42b
Show file tree
Hide file tree
Showing 10 changed files with 311 additions and 21 deletions.
35 changes: 32 additions & 3 deletions clients/rancher/catalog/clusterrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,51 @@ const (
chartsURL = "v1/catalog.cattle.io.clusterrepos/"
link = "link"
index = "index"
info = "info"
install = "install"
RancherChartRepo = "rancher-charts"
rancherAppsURL = "v1/catalog.cattle.io.apps/"
upgrade = "upgrade"
uninstall = "uninstall"
chartName = "chartName"
icon = "icon"
version = "version"
values = "values"
)

// FetchChartIcon - fetches the chart icon from the given repo, chart and version and validates the result
func (c *Client) FetchChartIcon(repo, chart, version string) (int, error) {
// GetChartValues - fetches the chart values from the given repo, chart and chartVersion and validates the result.
func (c *Client) GetChartValues(repoName, chart, chartVersion string) (map[string]interface{}, error) {
result, err := c.RESTClient().Get().
AbsPath(chartsURL+repoName).Param(link, info).Param(chartName, chart).Param(version, chartVersion).
Do(context.Background()).Raw()

if err != nil {
return map[string]interface{}{}, err
}

var mapResponse map[string]interface{}
if err = json.Unmarshal(result, &mapResponse); err != nil {
return map[string]interface{}{}, err
}

values, ok := mapResponse[values].(map[string]interface{})
if !ok {
return map[string]interface{}{}, fmt.Errorf("failed to convert values to map[string]interface{}")
}

return values, nil
}

// FetchChartIcon - fetches the chart icon from the given repo and chart and validates the result.
func (c *Client) FetchChartIcon(repo, chart string) (int, error) {
resp := c.RESTClient().Get().
AbsPath(chartsURL+repo).
Param(chartName, chart).Param(link, icon).
VersionedParams(&metav1.GetOptions{}, scheme.ParameterCodec).
Do(context.Background())

var contentType string

resp.ContentType(&contentType)

result, err := resp.Raw()
Expand All @@ -51,11 +78,13 @@ func (c *Client) FetchChartIcon(repo, chart, version string) (int, error) {

if contentType == "image/svg+xml" {
var xmlData interface{}

err = xml.Unmarshal(result, &xmlData)
if err != nil {
// If XML parsing fails, this is not a valid svg
return 0, err
}

return len(result), nil // Valid SVG
}

Expand Down Expand Up @@ -119,7 +148,7 @@ func (c *Client) GetListChartVersions(chartName, repoName string) ([]string, err
versionsList := []string{}
for _, entry := range specifiedChartEntries {
entryMap := entry.(map[string]interface{})
versionsList = append(versionsList, entryMap["version"].(string))
versionsList = append(versionsList, entryMap[version].(string))
}

return versionsList, nil
Expand Down
178 changes: 178 additions & 0 deletions extensions/charts/vsphereoutoftree.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package charts

import (
"github.com/rancher/shepherd/extensions/projects"
"github.com/rancher/shepherd/extensions/rke1/nodetemplates"
"github.com/rancher/shepherd/pkg/api/steve/catalog/types"

"github.com/rancher/shepherd/clients/rancher"
"github.com/rancher/shepherd/clients/rancher/catalog"
r1vsphere "github.com/rancher/shepherd/extensions/rke1/nodetemplates/vsphere"
)

const (
systemProject = "System"
vsphereCPIchartName = "rancher-vsphere-cpi"
vsphereCSIchartName = "rancher-vsphere-csi"

vcenter = "vCenter"
storageclass = "storageClass"

datacenters = "datacenters"
host = "host"
password = "password"
username = "username"
port = "port"
clusterid = "clusterId"
datastoreurl = "datastoreURL"
)

// InstallVsphereOutOfTreeCharts installs the CPI and CSI chart for aws cloud provider in a given cluster.
func InstallVsphereOutOfTreeCharts(client *rancher.Client, vsphereTemplate *nodetemplates.NodeTemplate, repoName, clusterID string) error {

serverSetting, err := client.Management.Setting.ByID(serverURLSettingID)
if err != nil {
return err
}

registrySetting, err := client.Management.Setting.ByID(defaultRegistrySettingID)
if err != nil {
return err
}

project, err := projects.GetProjectByName(client, clusterID, systemProject)
if err != nil {
return err
}

catalogClient, err := client.GetClusterCatalogClient(clusterID)
if err != nil {
return err
}

latestCPIVersion, err := catalogClient.GetLatestChartVersion(vsphereCPIchartName, catalog.RancherChartRepo)
if err != nil {
return err
}

installCPIOptions := &InstallOptions{
ClusterID: clusterID,
Version: latestCPIVersion,
ProjectID: project.ID,
}

chartInstallActionPayload := &payloadOpts{
InstallOptions: *installCPIOptions,
Name: vsphereCPIchartName,
Namespace: kubeSystemNamespace,
Host: serverSetting.Value,
DefaultRegistry: registrySetting.Value,
}

chartInstallAction, err := vsphereCPIChartInstallAction(catalogClient,
chartInstallActionPayload, vsphereTemplate, installCPIOptions, repoName, kubeSystemNamespace)
if err != nil {
return err
}

err = catalogClient.InstallChart(chartInstallAction, repoName)
if err != nil {
return err
}

err = VerifyChartInstall(catalogClient, kubeSystemNamespace, vsphereCPIchartName)
if err != nil {
return err
}

latestCSIVersion, err := catalogClient.GetLatestChartVersion(vsphereCSIchartName, catalog.RancherChartRepo)
if err != nil {
return err
}

installCSIOptions := &InstallOptions{
ClusterID: clusterID,
Version: latestCSIVersion,
ProjectID: project.ID,
}

chartInstallActionPayload = &payloadOpts{
InstallOptions: *installCSIOptions,
Name: vsphereCSIchartName,
Namespace: kubeSystemNamespace,
Host: serverSetting.Value,
DefaultRegistry: registrySetting.Value,
}

chartInstallAction, err = vsphereCSIChartInstallAction(catalogClient, chartInstallActionPayload,
vsphereTemplate, installCSIOptions, repoName, kubeSystemNamespace)
if err != nil {
return err
}

err = catalogClient.InstallChart(chartInstallAction, repoName)
if err != nil {
return err
}

return err
}

// vsphereCPIChartInstallAction is a helper function that returns a chartInstallAction for aws out-of-tree chart.
func vsphereCPIChartInstallAction(client *catalog.Client, chartInstallActionPayload *payloadOpts, vsphereTemplate *nodetemplates.NodeTemplate, installOptions *InstallOptions, repoName, chartNamespace string) (*types.ChartInstallAction, error) {
chartValues, err := client.GetChartValues(repoName, vsphereCPIchartName, installOptions.Version)
if err != nil {
return nil, err
}

chartValues[vcenter].(map[string]interface{})[datacenters] = vsphereTemplate.VmwareVsphereNodeTemplateConfig.Datacenter
chartValues[vcenter].(map[string]interface{})[host] = vsphereTemplate.VmwareVsphereNodeTemplateConfig.Vcenter
chartValues[vcenter].(map[string]interface{})[password] = r1vsphere.GetVspherePassword()
chartValues[vcenter].(map[string]interface{})[username] = vsphereTemplate.VmwareVsphereNodeTemplateConfig.Username
chartValues[vcenter].(map[string]interface{})[port] = vsphereTemplate.VmwareVsphereNodeTemplateConfig.VcenterPort

chartInstall := newChartInstall(
chartInstallActionPayload.Name,
chartInstallActionPayload.InstallOptions.Version,
chartInstallActionPayload.InstallOptions.ClusterID,
chartInstallActionPayload.InstallOptions.ClusterName,
chartInstallActionPayload.Host,
repoName,
installOptions.ProjectID,
chartInstallActionPayload.DefaultRegistry,
chartValues)
chartInstalls := []types.ChartInstall{*chartInstall}

return newChartInstallAction(chartNamespace, chartInstallActionPayload.ProjectID, chartInstalls), nil
}

// vsphereCSIChartInstallAction is a helper function that returns a chartInstallAction for aws out-of-tree chart.
func vsphereCSIChartInstallAction(client *catalog.Client, chartInstallActionPayload *payloadOpts, vsphereTemplate *nodetemplates.NodeTemplate, installOptions *InstallOptions, repoName, chartNamespace string) (*types.ChartInstallAction, error) {
chartValues, err := client.GetChartValues(repoName, vsphereCSIchartName, installOptions.Version)
if err != nil {
return nil, err
}

chartValues[vcenter].(map[string]interface{})[datacenters] = vsphereTemplate.VmwareVsphereNodeTemplateConfig.Datacenter
chartValues[vcenter].(map[string]interface{})[host] = vsphereTemplate.VmwareVsphereNodeTemplateConfig.Vcenter
chartValues[vcenter].(map[string]interface{})[password] = r1vsphere.GetVspherePassword()
chartValues[vcenter].(map[string]interface{})[username] = vsphereTemplate.VmwareVsphereNodeTemplateConfig.Username
chartValues[vcenter].(map[string]interface{})[port] = vsphereTemplate.VmwareVsphereNodeTemplateConfig.VcenterPort
chartValues[vcenter].(map[string]interface{})[clusterid] = installOptions.ClusterID

chartValues[storageclass].(map[string]interface{})[datastoreurl] = r1vsphere.GetVsphereDatastoreUrl()

chartInstall := newChartInstall(
chartInstallActionPayload.Name,
chartInstallActionPayload.InstallOptions.Version,
chartInstallActionPayload.InstallOptions.ClusterID,
chartInstallActionPayload.InstallOptions.ClusterName,
chartInstallActionPayload.Host,
repoName,
installOptions.ProjectID,
chartInstallActionPayload.DefaultRegistry,
chartValues)
chartInstalls := []types.ChartInstall{*chartInstall}

return newChartInstallAction(chartNamespace, chartInstallActionPayload.ProjectID, chartInstalls), nil
}
8 changes: 8 additions & 0 deletions extensions/cloudcredentials/vsphere/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,11 @@ func CreateVsphereCloudCredentials(rancherClient *rancher.Client) (*cloudcredent
}
return resp, nil
}

func GetVspherePassword() string {
var vmwarevsphereCredentialConfig cloudcredentials.VmwarevsphereCredentialConfig

config.LoadConfig(cloudcredentials.VmwarevsphereCredentialConfigurationFileKey, &vmwarevsphereCredentialConfig)

return vmwarevsphereCredentialConfig.Password
}
10 changes: 10 additions & 0 deletions extensions/clusters/clusters.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,16 @@ func NewK3SRKE2ClusterConfig(clusterName, namespace string, clustersConfig *Clus
machineSelectorConfigs = append(machineSelectorConfigs, awsOutOfTreeSystemConfig()...)
}

if clustersConfig.CloudProvider == provisioninginput.VsphereCloudProviderName.String() {
machineSelectorConfigs = append(machineSelectorConfigs,
RKESystemConfigTemplate(map[string]interface{}{
cloudProviderAnnotationName: provisioninginput.VsphereCloudProviderName.String(),
protectKernelDefaults: false,
},
nil),
)
}

rkeSpecCommon := rkev1.RKEClusterSpecCommon{
UpgradeStrategy: upgradeStrategy,
ChartValues: chartValuesMap,
Expand Down
12 changes: 7 additions & 5 deletions extensions/machinepools/vsphere_machine_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ const (
type VmwarevsphereMachineConfigs struct {
VmwarevsphereMachineConfig []VmwarevsphereMachineConfig `json:"vmwarevsphereMachineConfig" yaml:"vmwarevsphereMachineConfig"`

Hostsystem string `json:"hostsystem" yaml:"hostsystem"`
Datacenter string `json:"datacenter" yaml:"datacenter"`
Datastore string `json:"datastore" yaml:"datastore"`
Folder string `json:"folder" yaml:"folder"`
Pool string `json:"pool" yaml:"pool"`
Hostsystem string `json:"hostsystem" yaml:"hostsystem"`
Datacenter string `json:"datacenter" yaml:"datacenter"`
Datastore string `json:"datastore" yaml:"datastore"`
DatastoreUrl string `json:"datastoreUrl" yaml:"datastoreUrl"`
Folder string `json:"folder" yaml:"folder"`
Pool string `json:"pool" yaml:"pool"`
}

// VsphereMachineConfig is configuration needed to create an rke-machine-config.cattle.io.vmwarevsphereconfig
Expand Down Expand Up @@ -77,6 +78,7 @@ func NewVSphereMachineConfig(generatedPoolName, namespace string) []unstructured
machineConfig.Object["datacenter"] = vmwarevsphereMachineConfigs.Datacenter
machineConfig.Object["datastore"] = vmwarevsphereMachineConfigs.Datastore
machineConfig.Object["datastoreCluster"] = vsphereMachineConfig.DatastoreCluster
machineConfig.Object["datastoreUrl"] = vmwarevsphereMachineConfigs.DatastoreUrl
machineConfig.Object["diskSize"] = vsphereMachineConfig.DiskSize
machineConfig.Object["folder"] = vmwarevsphereMachineConfigs.Folder
machineConfig.Object["hostsystem"] = vmwarevsphereMachineConfigs.Hostsystem
Expand Down
Loading

0 comments on commit b5ca42b

Please sign in to comment.