
Updates reference for airshipctl modules and preserves existing airship UI functionality. Known issue: this update introduces an "overwrite" flag in ctl's config package that will need to be incorporated into the UI when an airship config file is initialized Change-Id: I168592fa2c662c151e22519f1e9e445416610143
514 lines
13 KiB
Go
514 lines
13 KiB
Go
/*
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package ctl
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
ctlconfig "opendev.org/airship/airshipctl/pkg/config"
|
|
"opendev.org/airship/airshipui/pkg/configs"
|
|
)
|
|
|
|
// ConfigFunctionMap is being used to call the appropriate function based on the SubComponentType,
|
|
// since the linter seems to think there are too many cases for a switch / case
|
|
var ConfigFunctionMap = map[configs.WsSubComponentType]func(configs.WsMessage) configs.WsMessage{
|
|
configs.SetAirshipConfig: SetAirshipConfig,
|
|
configs.GetAirshipConfigPath: GetAirshipConfigPath,
|
|
configs.GetCurrentContext: GetCurrentContext,
|
|
configs.GetContexts: GetContexts,
|
|
configs.GetEncryptionConfigs: GetEncryptionConfigs,
|
|
configs.GetManagementConfigs: GetManagementConfigs,
|
|
configs.GetManifests: GetManifests,
|
|
configs.Init: InitAirshipConfig,
|
|
configs.SetContext: SetContext,
|
|
configs.SetEncryptionConfig: SetEncryptionConfig,
|
|
configs.SetManagementConfig: SetManagementConfig,
|
|
configs.SetManifest: SetManifest,
|
|
configs.UseContext: UseContext,
|
|
}
|
|
|
|
// helper function to create most of the relevant bits of the response message
|
|
func newResponse(request configs.WsMessage) configs.WsMessage {
|
|
return configs.WsMessage{
|
|
Type: configs.CTL,
|
|
Component: configs.CTLConfig,
|
|
SubComponent: request.SubComponent,
|
|
Name: request.Name,
|
|
}
|
|
}
|
|
|
|
// HandleConfigRequest will find the appropriate subcomponent function in the function map
|
|
// and wait for it to complete before returning the response message
|
|
func HandleConfigRequest(user *string, request configs.WsMessage) configs.WsMessage {
|
|
var response configs.WsMessage
|
|
|
|
if handler, ok := ConfigFunctionMap[request.SubComponent]; ok {
|
|
response = handler(request)
|
|
} else {
|
|
response = newResponse(request)
|
|
err := fmt.Sprintf("Subcomponent %s not found", request.SubComponent)
|
|
response.Error = &err
|
|
}
|
|
|
|
return response
|
|
}
|
|
|
|
// GetAirshipConfigPath returns value stored in AirshipConfigPath
|
|
func GetAirshipConfigPath(request configs.WsMessage) configs.WsMessage {
|
|
response := newResponse(request)
|
|
|
|
// leave message empty if the file doesn't exist
|
|
if configFileExists(configs.UIConfig.AirshipConfigPath) {
|
|
response.Message = configs.UIConfig.AirshipConfigPath
|
|
}
|
|
|
|
return response
|
|
}
|
|
|
|
// SetAirshipConfig sets the AirshipConfigPath to the value specified by
|
|
// UI client
|
|
func SetAirshipConfig(request configs.WsMessage) configs.WsMessage {
|
|
response := newResponse(request)
|
|
|
|
configs.UIConfig.AirshipConfigPath = request.Message
|
|
err := configs.UIConfig.Persist()
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
msg := fmt.Sprintf("Config file set to '%s'", *configs.UIConfig.AirshipConfigPath)
|
|
response.Message = &msg
|
|
|
|
return response
|
|
}
|
|
|
|
// GetCurrentContext returns the name of the currently configured context
|
|
func GetCurrentContext(request configs.WsMessage) configs.WsMessage {
|
|
response := newResponse(request)
|
|
|
|
client, err := NewClient(configs.UIConfig.AirshipConfigPath, request)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
response.Message = &client.Config.CurrentContext
|
|
|
|
return response
|
|
}
|
|
|
|
// InitAirshipConfig wrapper function for CTL's CreateConfig using the specified path
|
|
// TODO(mfuller): we'll need to persist this info in airshipui.json so that we can
|
|
// set AirshipConfigPath at app launch
|
|
func InitAirshipConfig(request configs.WsMessage) configs.WsMessage {
|
|
response := newResponse(request)
|
|
|
|
confPath := *request.Message
|
|
if confPath == "" {
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
confPath = filepath.Join(home, ".airship", "config")
|
|
}
|
|
|
|
// TODO(mfuller): create a checkbox in frontend to allow setting of 'overwrite'
|
|
// This will probably require a InitOptions struct to capture the path and overwrite
|
|
// value, and it'll need to be sent in the Data message field. For now, we'll
|
|
// leave it set to a default of 'false'
|
|
overwrite := false
|
|
|
|
err := ctlconfig.CreateConfig(confPath, overwrite)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
configs.UIConfig.AirshipConfigPath = &confPath
|
|
// save this location back to airshipui config file so we'll remember it for next time
|
|
err = configs.UIConfig.Persist()
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
msg := fmt.Sprintf("Config file set to '%s'", *configs.UIConfig.AirshipConfigPath)
|
|
|
|
response.Message = &msg
|
|
|
|
return response
|
|
}
|
|
|
|
// Context wrapper struct to include context name with CTL's Context
|
|
type Context struct {
|
|
Name string `json:"name"`
|
|
ctlconfig.Context
|
|
}
|
|
|
|
// GetContexts returns a slice of wrapper Context structs so we know the name of each
|
|
// for display in the UI
|
|
func GetContexts(request configs.WsMessage) configs.WsMessage {
|
|
response := newResponse(request)
|
|
|
|
client, err := NewClient(configs.UIConfig.AirshipConfigPath, request)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
contexts := []Context{}
|
|
for name, context := range client.Config.Contexts {
|
|
contexts = append(contexts, Context{
|
|
name,
|
|
ctlconfig.Context{
|
|
NameInKubeconf: context.NameInKubeconf,
|
|
Manifest: context.Manifest,
|
|
EncryptionConfig: context.EncryptionConfig,
|
|
ManagementConfiguration: context.ManagementConfiguration,
|
|
},
|
|
})
|
|
}
|
|
|
|
response.Data = contexts
|
|
|
|
return response
|
|
}
|
|
|
|
// Manifest wraps CTL's Manifest to include the manifest name
|
|
type Manifest struct {
|
|
Name string `json:"name"`
|
|
Manifest *ctlconfig.Manifest `json:"manifest"`
|
|
}
|
|
|
|
// GetManifests returns a slice of wrapper Manifest structs so we know the name of each
|
|
// for display in the UI
|
|
func GetManifests(request configs.WsMessage) configs.WsMessage {
|
|
response := newResponse(request)
|
|
|
|
client, err := NewClient(configs.UIConfig.AirshipConfigPath, request)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
manifests := []Manifest{}
|
|
|
|
for name, manifest := range client.Config.Manifests {
|
|
manifests = append(manifests, Manifest{
|
|
Name: name,
|
|
Manifest: manifest,
|
|
})
|
|
}
|
|
|
|
response.Data = manifests
|
|
|
|
return response
|
|
}
|
|
|
|
// ManagementConfig wrapper struct for CTL's ManagementConfiguration that
|
|
// includes a name
|
|
type ManagementConfig struct {
|
|
Name string `json:"Name"`
|
|
ctlconfig.ManagementConfiguration
|
|
}
|
|
|
|
// GetManagementConfigs function to retrieve all management configs
|
|
func GetManagementConfigs(request configs.WsMessage) configs.WsMessage {
|
|
response := newResponse(request)
|
|
|
|
client, err := NewClient(configs.UIConfig.AirshipConfigPath, request)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
configs := []ManagementConfig{}
|
|
for name, conf := range client.Config.ManagementConfiguration {
|
|
configs = append(configs, ManagementConfig{
|
|
name,
|
|
ctlconfig.ManagementConfiguration{
|
|
Insecure: conf.Insecure,
|
|
SystemActionRetries: conf.SystemActionRetries,
|
|
SystemRebootDelay: conf.SystemRebootDelay,
|
|
Type: conf.Type,
|
|
UseProxy: conf.UseProxy,
|
|
},
|
|
})
|
|
}
|
|
|
|
response.Data = configs
|
|
|
|
return response
|
|
}
|
|
|
|
// EncryptionConfig wrapper struct for CTL's EncryptionConfiguration that
|
|
// includes a name
|
|
type EncryptionConfig struct {
|
|
Name string `json:"name"`
|
|
ctlconfig.EncryptionConfig
|
|
}
|
|
|
|
// GetEncryptionConfigs returns a slice of wrapper EncryptionConfig structs so we
|
|
// know the name of each for display in the UI
|
|
func GetEncryptionConfigs(request configs.WsMessage) configs.WsMessage {
|
|
response := newResponse(request)
|
|
|
|
client, err := NewClient(configs.UIConfig.AirshipConfigPath, request)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
configs := []EncryptionConfig{}
|
|
for name, config := range client.Config.EncryptionConfigs {
|
|
configs = append(configs, EncryptionConfig{
|
|
name,
|
|
ctlconfig.EncryptionConfig{
|
|
EncryptionKeyFileSource: config.EncryptionKeyFileSource,
|
|
EncryptionKeySecretSource: config.EncryptionKeySecretSource,
|
|
},
|
|
})
|
|
}
|
|
|
|
response.Data = configs
|
|
|
|
return response
|
|
}
|
|
|
|
// SetContext wrapper function for CTL's RunSetContext, using a UI client
|
|
func SetContext(request configs.WsMessage) configs.WsMessage {
|
|
response := newResponse(request)
|
|
|
|
client, err := NewClient(configs.UIConfig.AirshipConfigPath, request)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
bytes, err := json.Marshal(request.Data)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
var opts ctlconfig.ContextOptions
|
|
err = json.Unmarshal(bytes, &opts)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
err = opts.Validate()
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
_, err = ctlconfig.RunSetContext(&opts, client.Config, true)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
msg := fmt.Sprintf("Context '%s' has been modified", request.Name)
|
|
response.Message = &msg
|
|
|
|
return response
|
|
}
|
|
|
|
// SetEncryptionConfig wrapper function for CTL's RunSetEncryptionConfig, using a UI client
|
|
func SetEncryptionConfig(request configs.WsMessage) configs.WsMessage {
|
|
response := newResponse(request)
|
|
|
|
client, err := NewClient(configs.UIConfig.AirshipConfigPath, request)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
bytes, err := json.Marshal(request.Data)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
var opts ctlconfig.EncryptionConfigOptions
|
|
err = json.Unmarshal(bytes, &opts)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
err = opts.Validate()
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
_, err = ctlconfig.RunSetEncryptionConfig(&opts, client.Config, true)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
msg := fmt.Sprintf("Encryption configuration '%s' has been modified", request.Name)
|
|
response.Message = &msg
|
|
|
|
return response
|
|
}
|
|
|
|
// SetManagementConfig sets the specified management configuration with values
|
|
// received from the frontend client
|
|
// TODO(mfuller): there's currently no setter for this in the CTL config pkg
|
|
// so we'll set the values manually and then persist the config
|
|
func SetManagementConfig(request configs.WsMessage) configs.WsMessage {
|
|
response := newResponse(request)
|
|
|
|
client, err := NewClient(configs.UIConfig.AirshipConfigPath, request)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
bytes, err := json.Marshal(request.Data)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
var mCfg ctlconfig.ManagementConfiguration
|
|
|
|
err = json.Unmarshal(bytes, &mCfg)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
client.Config.ManagementConfiguration[request.Name] = &mCfg
|
|
|
|
// since we're either creating a new management config or modifying an existing
|
|
// one in a known airship config file, we'll assume 'overwrite' to be true
|
|
overwrite := true
|
|
|
|
err = client.Config.PersistConfig(overwrite)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
msg := fmt.Sprintf("Management configuration '%s' has been modified", request.Name)
|
|
response.Message = &msg
|
|
|
|
return response
|
|
}
|
|
|
|
// SetManifest wrapper function for CTL's RunSetManifest, using a UI client
|
|
func SetManifest(request configs.WsMessage) configs.WsMessage {
|
|
response := newResponse(request)
|
|
|
|
client, err := NewClient(configs.UIConfig.AirshipConfigPath, request)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
bytes, err := json.Marshal(request.Data)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
var opts ctlconfig.ManifestOptions
|
|
err = json.Unmarshal(bytes, &opts)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
err = opts.Validate()
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
_, err = ctlconfig.RunSetManifest(&opts, client.Config, true)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
msg := fmt.Sprintf("Manifest '%s' has been modified", request.Name)
|
|
response.Message = &msg
|
|
|
|
return response
|
|
}
|
|
|
|
// UseContext wrapper function for CTL's RunUseConfig, using a UI client
|
|
func UseContext(request configs.WsMessage) configs.WsMessage {
|
|
response := newResponse(request)
|
|
|
|
client, err := NewClient(configs.UIConfig.AirshipConfigPath, request)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
err = ctlconfig.RunUseContext(request.Name, client.Config)
|
|
if err != nil {
|
|
e := err.Error()
|
|
response.Error = &e
|
|
return response
|
|
}
|
|
|
|
msg := fmt.Sprintf("Using context '%s'", request.Name)
|
|
response.Message = &msg
|
|
|
|
return response
|
|
}
|