2019-10-24 10:59:58 +02:00
package cmd
import (
"fmt"
"io"
"os"
"github.com/SAP/jenkins-library/pkg/config"
2019-11-07 09:17:42 +02:00
"github.com/SAP/jenkins-library/pkg/piperutils"
2019-10-24 10:59:58 +02:00
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
type configCommandOptions struct {
output string //output format, so far only JSON
parametersJSON string //parameters to be considered in JSON format
stepMetadata string //metadata to be considered, can be filePath or ENV containing JSON in format 'ENV:MY_ENV_VAR'
stepName string
contextConfig bool
openFile func ( s string ) ( io . ReadCloser , error )
}
var configOptions configCommandOptions
// ConfigCommand is the entry command for loading the configuration of a pipeline step
func ConfigCommand ( ) * cobra . Command {
2019-11-21 17:09:57 +02:00
configOptions . openFile = config . OpenPiperFile
2019-10-24 10:59:58 +02:00
var createConfigCmd = & cobra . Command {
Use : "getConfig" ,
Short : "Loads the project 'Piper' configuration respecting defaults and parameters." ,
RunE : func ( cmd * cobra . Command , _ [ ] string ) error {
return generateConfig ( )
} ,
}
addConfigFlags ( createConfigCmd )
return createConfigCmd
}
func generateConfig ( ) error {
var myConfig config . Config
var stepConfig config . StepConfig
var metadata config . StepData
metadataFile , err := configOptions . openFile ( configOptions . stepMetadata )
if err != nil {
return errors . Wrap ( err , "metadata: open failed" )
}
err = metadata . ReadPipelineStepData ( metadataFile )
if err != nil {
return errors . Wrap ( err , "metadata: read failed" )
}
2020-01-15 13:16:25 +02:00
resourceParams := metadata . GetResourceParameters ( GeneralConfig . EnvRootPath , "commonPipelineEnvironment" )
2019-11-06 11:28:15 +02:00
var customConfig io . ReadCloser
2019-12-11 11:13:23 +02:00
{
exists , e := piperutils . FileExists ( GeneralConfig . CustomConfig )
if e != nil {
return e
}
if exists {
customConfig , err = configOptions . openFile ( GeneralConfig . CustomConfig )
if err != nil {
return errors . Wrap ( err , "config: open failed" )
}
2019-11-06 11:28:15 +02:00
}
2019-10-24 10:59:58 +02:00
}
2019-11-22 11:14:21 +02:00
defaultConfig , paramFilter , err := defaultsAndFilters ( & metadata , metadata . Metadata . Name )
2019-10-24 10:59:58 +02:00
if err != nil {
return errors . Wrap ( err , "defaults: retrieving step defaults failed" )
}
2019-11-06 17:22:50 +02:00
for _ , f := range GeneralConfig . DefaultConfig {
2019-10-24 10:59:58 +02:00
fc , err := configOptions . openFile ( f )
2019-11-21 17:09:57 +02:00
// only create error for non-default values
if err != nil && f != ".pipeline/defaults.yaml" {
2019-10-24 10:59:58 +02:00
return errors . Wrapf ( err , "config: getting defaults failed: '%v'" , f )
}
defaultConfig = append ( defaultConfig , fc )
}
var flags map [ string ] interface { }
2019-10-29 11:58:24 +02:00
params := [ ] config . StepParameters { }
if ! configOptions . contextConfig {
params = metadata . Spec . Inputs . Parameters
}
2020-03-19 18:24:35 +02:00
stepConfig , err = myConfig . GetStepConfig ( flags , GeneralConfig . ParametersJSON , customConfig , defaultConfig , paramFilter , params , resourceParams , GeneralConfig . StageName , metadata . Metadata . Name , metadata . Metadata . Aliases )
2019-10-24 10:59:58 +02:00
if err != nil {
return errors . Wrap ( err , "getting step config failed" )
}
2020-01-24 15:30:27 +02:00
// apply context conditions if context configuration is requested
if configOptions . contextConfig {
applyContextConditions ( metadata , & stepConfig )
}
2019-10-24 10:59:58 +02:00
myConfigJSON , _ := config . GetJSON ( stepConfig . Config )
fmt . Println ( myConfigJSON )
return nil
}
func addConfigFlags ( cmd * cobra . Command ) {
//ToDo: support more output options, like https://kubernetes.io/docs/reference/kubectl/overview/#formatting-output
cmd . Flags ( ) . StringVar ( & configOptions . output , "output" , "json" , "Defines the output format" )
cmd . Flags ( ) . StringVar ( & configOptions . parametersJSON , "parametersJSON" , os . Getenv ( "PIPER_parametersJSON" ) , "Parameters to be considered in JSON format" )
cmd . Flags ( ) . StringVar ( & configOptions . stepMetadata , "stepMetadata" , "" , "Step metadata, passed as path to yaml" )
cmd . Flags ( ) . BoolVar ( & configOptions . contextConfig , "contextConfig" , false , "Defines if step context configuration should be loaded instead of step config" )
cmd . MarkFlagRequired ( "stepMetadata" )
}
2019-11-22 11:14:21 +02:00
func defaultsAndFilters ( metadata * config . StepData , stepName string ) ( [ ] io . ReadCloser , config . StepFilters , error ) {
2019-10-24 10:59:58 +02:00
if configOptions . contextConfig {
2019-11-22 11:14:21 +02:00
defaults , err := metadata . GetContextDefaults ( stepName )
2019-10-24 10:59:58 +02:00
if err != nil {
return nil , config . StepFilters { } , errors . Wrap ( err , "metadata: getting context defaults failed" )
}
return [ ] io . ReadCloser { defaults } , metadata . GetContextParameterFilters ( ) , nil
}
//ToDo: retrieve default values from metadata
return nil , metadata . GetParameterFilters ( ) , nil
}
2020-01-24 15:30:27 +02:00
func applyContextConditions ( metadata config . StepData , stepConfig * config . StepConfig ) {
//consider conditions for context configuration
//containers
applyContainerConditions ( metadata . Spec . Containers , stepConfig )
//sidecars
applyContainerConditions ( metadata . Spec . Sidecars , stepConfig )
//ToDo: remove all unnecessary sub maps?
// e.g. extract delete() from applyContainerConditions - loop over all stepConfig.Config[param.Value] and remove ...
}
func applyContainerConditions ( containers [ ] config . Container , stepConfig * config . StepConfig ) {
for _ , container := range containers {
if len ( container . Conditions ) > 0 {
for _ , param := range container . Conditions [ 0 ] . Params {
if container . Conditions [ 0 ] . ConditionRef == "strings-equal" && stepConfig . Config [ param . Name ] == param . Value {
var containerConf map [ string ] interface { }
containerConf = stepConfig . Config [ param . Value ] . ( map [ string ] interface { } )
for key , value := range containerConf {
stepConfig . Config [ key ] = value
}
delete ( stepConfig . Config , param . Value )
}
}
}
}
}