github.com/Axway/agent-sdk@v1.1.101/pkg/config/centralconfig.go (about)

     1  package config
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net/url"
     7  	"os"
     8  	"strings"
     9  	"time"
    10  
    11  	v1 "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/api/v1"
    12  	mv1 "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/management/v1alpha1"
    13  	"github.com/Axway/agent-sdk/pkg/cmd/properties"
    14  	"github.com/Axway/agent-sdk/pkg/util/exception"
    15  	"github.com/Axway/agent-sdk/pkg/util/log"
    16  	"github.com/gorhill/cronexpr"
    17  )
    18  
    19  const urlCutSet = " /"
    20  
    21  type Region int
    22  
    23  const (
    24  	US Region = iota + 1
    25  	EU
    26  	AP
    27  )
    28  
    29  var regionNamesMap = map[Region]string{
    30  	US: "US",
    31  	EU: "EU",
    32  	AP: "AP",
    33  }
    34  
    35  var nameToRegionMap = map[string]Region{
    36  	"US": US,
    37  	"EU": EU,
    38  	"AP": AP,
    39  }
    40  
    41  func (r Region) ToString() string {
    42  	return regionNamesMap[r]
    43  }
    44  
    45  type regionalSettings struct {
    46  	SingleURL        string
    47  	CentralURL       string
    48  	AuthURL          string
    49  	PlatformURL      string
    50  	TraceabilityHost string
    51  	Deployment       string
    52  }
    53  
    54  var regionalSettingsMap = map[Region]regionalSettings{
    55  	US: {
    56  		SingleURL:        "https://ingestion.platform.axway.com",
    57  		CentralURL:       "https://apicentral.axway.com",
    58  		AuthURL:          "https://login.axway.com/auth",
    59  		PlatformURL:      "https://platform.axway.com",
    60  		TraceabilityHost: "ingestion.datasearch.axway.com:5044",
    61  		Deployment:       "prod",
    62  	},
    63  	EU: {
    64  		SingleURL:        "https://ingestion-eu.platform.axway.com",
    65  		CentralURL:       "https://central.eu-fr.axway.com",
    66  		AuthURL:          "https://login.axway.com/auth",
    67  		PlatformURL:      "https://platform.axway.com",
    68  		TraceabilityHost: "ingestion.visibility.eu-fr.axway.com:5044",
    69  		Deployment:       "prod-eu",
    70  	},
    71  	AP: {
    72  		SingleURL:        "https://ingestion-ap-sg.platform.axway.com",
    73  		CentralURL:       "https://central.ap-sg.axway.com",
    74  		AuthURL:          "https://login.axway.com/auth",
    75  		PlatformURL:      "https://platform.axway.com",
    76  		TraceabilityHost: "ingestion.visibility.ap-sg.axway.com:5044",
    77  		Deployment:       "prod-ap",
    78  	},
    79  }
    80  
    81  // AgentType - Defines the type of agent
    82  type AgentType int
    83  
    84  const (
    85  	// DiscoveryAgent - Type definition for discovery agent
    86  	DiscoveryAgent AgentType = iota + 1
    87  	// TraceabilityAgent - Type definition for traceability agent
    88  	TraceabilityAgent
    89  	// GovernanceAgent - Type definition for governance agent
    90  	GovernanceAgent
    91  	// GenericService - Type for a generic service
    92  	GenericService
    93  )
    94  
    95  var agentTypeNamesMap = map[AgentType]string{
    96  	DiscoveryAgent:    "discoveryagent",
    97  	TraceabilityAgent: "traceabilityagent",
    98  	GovernanceAgent:   "governanceagent",
    99  }
   100  
   101  var agentTypeShortNamesMap = map[AgentType]string{
   102  	DiscoveryAgent:    "da",
   103  	TraceabilityAgent: "ta",
   104  	GovernanceAgent:   "ga",
   105  }
   106  
   107  func (agentType AgentType) ToString() string {
   108  	return agentTypeNamesMap[agentType]
   109  }
   110  
   111  func (agentType AgentType) ToShortString() string {
   112  	return agentTypeShortNamesMap[agentType]
   113  }
   114  
   115  // subscription approval types
   116  const (
   117  	ManualApproval  string = "manual"
   118  	AutoApproval    string = "auto"
   119  	WebhookApproval string = "webhook"
   120  )
   121  
   122  // AgentTypeName - Holds the name Agent type
   123  var AgentTypeName string
   124  
   125  // AgentDisplayName - Holds the name Agent name for displaying in version command or elsewhere
   126  var AgentDisplayName string
   127  
   128  // AgentVersion - Holds the version of agent
   129  var AgentVersion string
   130  
   131  // AgentLatestVersion - Holds the latest version of the agent
   132  var AgentLatestVersion string
   133  
   134  // AgentDataPlaneType - Holds the data plane type of agent
   135  var AgentDataPlaneType string
   136  
   137  // SDKVersion - Holds the version of SDK
   138  var SDKVersion string
   139  
   140  // IConfigValidator - Interface to be implemented for config validation by agent
   141  type IConfigValidator interface {
   142  	ValidateCfg() error
   143  }
   144  
   145  // IResourceConfigCallback - Interface to be implemented by configs to apply API Server resource for agent
   146  type IResourceConfigCallback interface {
   147  	ApplyResources(agentResource *v1.ResourceInstance) error
   148  }
   149  
   150  // CentralConfig - Interface to get central Config
   151  type CentralConfig interface {
   152  	GetAgentType() AgentType
   153  	GetRegion() Region
   154  	GetTenantID() string
   155  	GetAPICDeployment() string
   156  	GetEnvironmentID() string
   157  	SetEnvironmentID(environmentID string)
   158  	IsAxwayManaged() bool
   159  	SetAxwayManaged(isAxwayManaged bool)
   160  	GetEnvironmentName() string
   161  	GetAgentName() string
   162  	GetTeamName() string
   163  	GetTeamID() string
   164  	SetTeamID(teamID string)
   165  	GetURL() string
   166  	GetTraceabilityHost() string
   167  	GetPlatformURL() string
   168  	GetAPIServerURL() string
   169  	GetEnvironmentURL() string
   170  	GetEnvironmentACLsURL() string
   171  	GetServicesURL() string
   172  	GetRevisionsURL() string
   173  	GetInstancesURL() string
   174  	DeleteServicesURL() string
   175  	GetAPIServerAccessRequestDefinitionURL() string
   176  	GetAPIServerSecretsURL() string
   177  	GetAccessRequestsURL() string
   178  	GetAccessRequestURL(string) string
   179  	GetAccessRequestStateURL(string) string
   180  	GetAuthConfig() AuthConfig
   181  	GetTLSConfig() TLSConfig
   182  	GetTagsToPublish() string
   183  	GetProxyURL() string
   184  	GetPollInterval() time.Duration
   185  	GetReportActivityFrequency() time.Duration
   186  	GetAPIValidationCronSchedule() string
   187  	GetJobExecutionTimeout() time.Duration
   188  	GetClientTimeout() time.Duration
   189  	GetPageSize() int
   190  	GetAPIServiceRevisionPattern() string
   191  	GetAppendEnvironmentToTitle() bool
   192  	GetUsageReportingConfig() UsageReportingConfig
   193  	GetMetricReportingConfig() MetricReportingConfig
   194  	IsUsingGRPC() bool
   195  	GetGRPCHost() string
   196  	GetGRPCPort() int
   197  	IsGRPCInsecure() bool
   198  	GetCacheStoragePath() string
   199  	GetCacheStorageInterval() time.Duration
   200  	GetSingleURL() string
   201  	GetMigrationSettings() MigrationConfig
   202  	GetWatchResourceFilters() []ResourceFilter
   203  	SetWatchResourceFilters([]ResourceFilter) error
   204  	GetCredentialConfig() CredentialConfig
   205  }
   206  
   207  // CentralConfiguration - Structure to hold the central config
   208  type CentralConfiguration struct {
   209  	CentralConfig
   210  	IConfigValidator
   211  	AgentType                 AgentType
   212  	RegionSettings            regionalSettings
   213  	Region                    Region                `config:"region"`
   214  	TenantID                  string                `config:"organizationID"`
   215  	TeamName                  string                `config:"team"`
   216  	APICDeployment            string                `config:"deployment"`
   217  	Environment               string                `config:"environment"`
   218  	EnvironmentID             string                `config:"environmentID"`
   219  	AgentName                 string                `config:"agentName"`
   220  	URL                       string                `config:"url"`
   221  	SingleURL                 string                `config:"platformSingleURL"`
   222  	PlatformURL               string                `config:"platformURL"`
   223  	APIServerVersion          string                `config:"apiServerVersion"`
   224  	TagsToPublish             string                `config:"additionalTags"`
   225  	AppendEnvironmentToTitle  bool                  `config:"appendEnvironmentToTitle"`
   226  	MigrationSettings         MigrationConfig       `config:"migration"`
   227  	Auth                      AuthConfig            `config:"auth"`
   228  	TLS                       TLSConfig             `config:"ssl"`
   229  	PollInterval              time.Duration         `config:"pollInterval"`
   230  	ReportActivityFrequency   time.Duration         `config:"reportActivityFrequency"`
   231  	ClientTimeout             time.Duration         `config:"clientTimeout"`
   232  	PageSize                  int                   `config:"pageSize"`
   233  	APIValidationCronSchedule string                `config:"apiValidationCronSchedule"`
   234  	APIServiceRevisionPattern string                `config:"apiServiceRevisionPattern"`
   235  	ProxyURL                  string                `config:"proxyUrl"`
   236  	UsageReporting            UsageReportingConfig  `config:"usageReporting"`
   237  	MetricReporting           MetricReportingConfig `config:"metricReporting"`
   238  	GRPCCfg                   GRPCConfig            `config:"grpc"`
   239  	CacheStoragePath          string                `config:"cacheStoragePath"`
   240  	CacheStorageInterval      time.Duration         `config:"cacheStorageInterval"`
   241  	CredentialConfig          CredentialConfig      `config:"credential"`
   242  	JobExecutionTimeout       time.Duration
   243  	environmentID             string
   244  	teamID                    string
   245  	isSingleURLSet            bool
   246  	isRegionSet               bool
   247  	isAxwayManaged            bool
   248  	WatchResourceFilters      []ResourceFilter
   249  }
   250  
   251  // GRPCConfig - Represents the grpc config
   252  type GRPCConfig struct {
   253  	Enabled  bool   `config:"enabled"`
   254  	Host     string `config:"host"`
   255  	Port     int    `config:"port"`
   256  	Insecure bool   `config:"insecure"`
   257  }
   258  
   259  // NewCentralConfig - Creates the default central config
   260  func NewCentralConfig(agentType AgentType) CentralConfig {
   261  	platformURL := "https://platform.axway.com"
   262  	return &CentralConfiguration{
   263  		AgentType:                 agentType,
   264  		Region:                    US,
   265  		TeamName:                  "",
   266  		APIServerVersion:          "v1alpha1",
   267  		Auth:                      newAuthConfig(),
   268  		TLS:                       NewTLSConfig(),
   269  		PollInterval:              60 * time.Second,
   270  		ClientTimeout:             60 * time.Second,
   271  		PageSize:                  100,
   272  		PlatformURL:               platformURL,
   273  		SingleURL:                 "",
   274  		AppendEnvironmentToTitle:  true,
   275  		ReportActivityFrequency:   5 * time.Minute,
   276  		APIValidationCronSchedule: "@daily",
   277  		UsageReporting:            NewUsageReporting(platformURL),
   278  		MetricReporting:           NewMetricReporting(),
   279  		JobExecutionTimeout:       5 * time.Minute,
   280  		CacheStorageInterval:      10 * time.Second,
   281  		GRPCCfg: GRPCConfig{
   282  			Enabled: true,
   283  		},
   284  		MigrationSettings: newMigrationConfig(),
   285  		CredentialConfig:  newCredentialConfig(),
   286  	}
   287  }
   288  
   289  // NewTestCentralConfig - Creates the default central config
   290  func NewTestCentralConfig(agentType AgentType) CentralConfig {
   291  	config := NewCentralConfig(agentType).(*CentralConfiguration)
   292  	config.TenantID = "1234567890"
   293  	config.Region = US
   294  	config.URL = "https://central.com"
   295  	config.PlatformURL = "https://platform.axway.com"
   296  	config.Environment = "environment"
   297  	config.environmentID = "env-id"
   298  	config.Auth = newTestAuthConfig()
   299  	config.MigrationSettings = newTestMigrationConfig()
   300  	if agentType == TraceabilityAgent {
   301  		config.APICDeployment = "deployment"
   302  	}
   303  	return config
   304  }
   305  
   306  // GetPlatformURL - Returns the central base URL
   307  func (c *CentralConfiguration) GetPlatformURL() string {
   308  	if c.PlatformURL == "" {
   309  		return c.RegionSettings.PlatformURL
   310  	}
   311  	return c.PlatformURL
   312  }
   313  
   314  // GetAgentType - Returns the agent type
   315  func (c *CentralConfiguration) GetAgentType() AgentType {
   316  	return c.AgentType
   317  }
   318  
   319  // GetRegion - Returns the region
   320  func (c *CentralConfiguration) GetRegion() Region {
   321  	return c.Region
   322  }
   323  
   324  // GetTenantID - Returns the tenant ID
   325  func (c *CentralConfiguration) GetTenantID() string {
   326  	return c.TenantID
   327  }
   328  
   329  // GetAPICDeployment - Returns the Central deployment type 'prod', 'preprod', team ('beano')
   330  func (c *CentralConfiguration) GetAPICDeployment() string {
   331  	if c.APICDeployment == "" {
   332  		return c.RegionSettings.Deployment
   333  	}
   334  	return c.APICDeployment
   335  }
   336  
   337  // GetEnvironmentID - Returns the environment ID
   338  func (c *CentralConfiguration) GetEnvironmentID() string {
   339  	return c.environmentID
   340  }
   341  
   342  // SetEnvironmentID - Sets the environment ID
   343  func (c *CentralConfiguration) SetEnvironmentID(environmentID string) {
   344  	c.environmentID = environmentID
   345  }
   346  
   347  // IsAxwayManaged - Returns the environment ID
   348  func (c *CentralConfiguration) IsAxwayManaged() bool {
   349  	return c.isAxwayManaged
   350  }
   351  
   352  // SetAxwayManaged - Sets the environment ID
   353  func (c *CentralConfiguration) SetAxwayManaged(isManaged bool) {
   354  	c.isAxwayManaged = isManaged
   355  }
   356  
   357  // GetEnvironmentName - Returns the environment name
   358  func (c *CentralConfiguration) GetEnvironmentName() string {
   359  	return c.Environment
   360  }
   361  
   362  // GetAgentName - Returns the agent name
   363  func (c *CentralConfiguration) GetAgentName() string {
   364  	return c.AgentName
   365  }
   366  
   367  // GetTeamName - Returns the team name
   368  func (c *CentralConfiguration) GetTeamName() string {
   369  	return c.TeamName
   370  }
   371  
   372  // GetTeamID - Returns the team ID
   373  func (c *CentralConfiguration) GetTeamID() string {
   374  	return c.teamID
   375  }
   376  
   377  // SetTeamID - Sets the team ID
   378  func (c *CentralConfiguration) SetTeamID(teamID string) {
   379  	c.teamID = teamID
   380  }
   381  
   382  // GetURL - Returns the central base URL
   383  func (c *CentralConfiguration) GetURL() string {
   384  	if c.URL == "" {
   385  		return c.RegionSettings.CentralURL
   386  	}
   387  	return c.URL
   388  }
   389  
   390  // GetTraceabilityHost - Returns the central traceability host
   391  func (c *CentralConfiguration) GetTraceabilityHost() string {
   392  	if c.isRegionSet {
   393  		return c.RegionSettings.TraceabilityHost
   394  	}
   395  	return ""
   396  }
   397  
   398  // GetProxyURL - Returns the central Proxy URL
   399  func (c *CentralConfiguration) GetProxyURL() string {
   400  	return c.ProxyURL
   401  }
   402  
   403  // GetAccessRequestsURL - Returns the accessrequest URL for access request API
   404  func (c *CentralConfiguration) GetAccessRequestsURL() string {
   405  	return c.GetEnvironmentURL() + "/accessrequests"
   406  }
   407  
   408  // GetAPIServerURL - Returns the base path for the API server
   409  func (c *CentralConfiguration) GetAPIServerURL() string {
   410  	return c.GetURL() + "/apis/management/" + c.APIServerVersion + "/environments/"
   411  }
   412  
   413  // GetEnvironmentURL - Returns the APIServer URL for services API
   414  func (c *CentralConfiguration) GetEnvironmentURL() string {
   415  	return c.GetAPIServerURL() + c.Environment
   416  }
   417  
   418  // GetEnvironmentACLsURL - Returns the APIServer URL for ACLs in Environments
   419  func (c *CentralConfiguration) GetEnvironmentACLsURL() string {
   420  	return c.GetEnvironmentURL() + "/accesscontrollists"
   421  }
   422  
   423  // GetServicesURL - Returns the APIServer URL for services API
   424  func (c *CentralConfiguration) GetServicesURL() string {
   425  	return c.GetEnvironmentURL() + "/apiservices"
   426  }
   427  
   428  // GetRevisionsURL - Returns the APIServer URL for services API revisions
   429  func (c *CentralConfiguration) GetRevisionsURL() string {
   430  	return c.GetEnvironmentURL() + "/apiservicerevisions"
   431  }
   432  
   433  // GetInstancesURL - Returns the APIServer URL for services API instances
   434  func (c *CentralConfiguration) GetInstancesURL() string {
   435  	return c.GetEnvironmentURL() + "/apiserviceinstances"
   436  }
   437  
   438  // DeleteServicesURL - Returns the APIServer URL for services API instances
   439  func (c *CentralConfiguration) DeleteServicesURL() string {
   440  	return c.GetEnvironmentURL() + "/apiservices"
   441  }
   442  
   443  // GetAPIServerAccessRequestDefinitionURL - Returns the APIServer URL for access request definitions
   444  func (c *CentralConfiguration) GetAPIServerAccessRequestDefinitionURL() string {
   445  	return c.GetEnvironmentURL() + "/accessrequestdefinitions"
   446  }
   447  
   448  // GetAPIServerSecretsURL - Returns the APIServer URL for secrets
   449  func (c *CentralConfiguration) GetAPIServerSecretsURL() string {
   450  	return c.GetEnvironmentURL() + "/secrets"
   451  }
   452  
   453  // GetAccessRequestURL - Returns the access request URL for catalog item subscription states
   454  func (c *CentralConfiguration) GetAccessRequestURL(accessRequestName string) string {
   455  	return fmt.Sprintf("%s/%s", c.GetAccessRequestsURL(), accessRequestName)
   456  }
   457  
   458  // GetAccessRequestStateURL - Returns the access request URL to update the state
   459  func (c *CentralConfiguration) GetAccessRequestStateURL(accessRequestName string) string {
   460  	return fmt.Sprintf("%s/state", c.GetAccessRequestURL(accessRequestName))
   461  }
   462  
   463  // GetAuthConfig - Returns the Auth Config
   464  func (c *CentralConfiguration) GetAuthConfig() AuthConfig {
   465  	return c.Auth
   466  }
   467  
   468  // GetMigrationSettings - Returns the Migration Config
   469  func (c *CentralConfiguration) GetMigrationSettings() MigrationConfig {
   470  	return c.MigrationSettings
   471  }
   472  
   473  // GetTLSConfig - Returns the TLS Config
   474  func (c *CentralConfiguration) GetTLSConfig() TLSConfig {
   475  	return c.TLS
   476  }
   477  
   478  // GetTagsToPublish - Returns tags to publish
   479  func (c *CentralConfiguration) GetTagsToPublish() string {
   480  	return c.TagsToPublish
   481  }
   482  
   483  // GetPollInterval - Returns the interval for polling subscriptions
   484  func (c *CentralConfiguration) GetPollInterval() time.Duration {
   485  	return c.PollInterval
   486  }
   487  
   488  // GetReportActivityFrequency - Returns the interval between running periodic status updater
   489  func (c *CentralConfiguration) GetReportActivityFrequency() time.Duration {
   490  	return c.ReportActivityFrequency
   491  }
   492  
   493  // GetAPIValidationCronSchedule - Returns the cron schedule running the api validator
   494  func (c *CentralConfiguration) GetAPIValidationCronSchedule() string {
   495  	return c.APIValidationCronSchedule
   496  }
   497  
   498  // GetJobExecutionTimeout - Returns the max time a job execution can run before considered failed
   499  func (c *CentralConfiguration) GetJobExecutionTimeout() time.Duration {
   500  	return c.JobExecutionTimeout
   501  }
   502  
   503  // GetClientTimeout - Returns the interval for http client timeouts
   504  func (c *CentralConfiguration) GetClientTimeout() time.Duration {
   505  	return c.ClientTimeout
   506  }
   507  
   508  // GetPageSize - Returns the page size for api server calls
   509  func (c *CentralConfiguration) GetPageSize() int {
   510  	return c.PageSize
   511  }
   512  
   513  // GetAPIServiceRevisionPattern - Returns the naming pattern for APIServiceRevition title
   514  func (c *CentralConfiguration) GetAPIServiceRevisionPattern() string {
   515  	return c.APIServiceRevisionPattern
   516  }
   517  
   518  // GetAppendEnvironmentToTitle - Returns the value of append environment name to title attribute
   519  func (c *CentralConfiguration) GetAppendEnvironmentToTitle() bool {
   520  	return c.AppendEnvironmentToTitle
   521  }
   522  
   523  // GetUsageReportingConfig -
   524  func (c *CentralConfiguration) GetUsageReportingConfig() UsageReportingConfig {
   525  	// Some paths in DA are checking usage reporting .  So return an empty usage reporting config if nil
   526  	// Find All References to see DA scenarios checking for this config
   527  	if c.UsageReporting == nil {
   528  		return NewUsageReporting(c.GetPlatformURL())
   529  	}
   530  	return c.UsageReporting
   531  }
   532  
   533  // GetMetricReportingConfig -
   534  func (c *CentralConfiguration) GetMetricReportingConfig() MetricReportingConfig {
   535  	// Some paths in DA are checking usage reporting .  So return an empty usage reporting config if nil
   536  	// Find All References to see DA scenarios checking for this config
   537  	if c.MetricReporting == nil {
   538  		return NewMetricReporting()
   539  	}
   540  	return c.MetricReporting
   541  }
   542  
   543  // GetCredentialConfig -
   544  func (c *CentralConfiguration) GetCredentialConfig() CredentialConfig {
   545  	return c.CredentialConfig
   546  }
   547  
   548  // IsUsingGRPC -
   549  func (c *CentralConfiguration) IsUsingGRPC() bool {
   550  	return c.GRPCCfg.Enabled
   551  }
   552  
   553  // GetGRPCHost -
   554  func (c *CentralConfiguration) GetGRPCHost() string {
   555  	return c.GRPCCfg.Host
   556  }
   557  
   558  // GetGRPCPort -
   559  func (c *CentralConfiguration) GetGRPCPort() int {
   560  	return c.GRPCCfg.Port
   561  }
   562  
   563  // IsGRPCInsecure -
   564  func (c *CentralConfiguration) IsGRPCInsecure() bool {
   565  	return c.GRPCCfg.Insecure
   566  }
   567  
   568  // GetCacheStoragePath -
   569  func (c *CentralConfiguration) GetCacheStoragePath() string {
   570  	return c.CacheStoragePath
   571  }
   572  
   573  // GetCacheStorageInterval -
   574  func (c *CentralConfiguration) GetCacheStorageInterval() time.Duration {
   575  	return c.CacheStorageInterval
   576  }
   577  
   578  // GetSingleURL - Returns the Alternate base URL
   579  func (c *CentralConfiguration) GetSingleURL() string {
   580  	if c.SingleURL == "" && !c.isSingleURLSet {
   581  		if c.isRegionSet {
   582  			return c.RegionSettings.SingleURL
   583  		}
   584  
   585  	}
   586  	return c.SingleURL
   587  }
   588  
   589  // GetWatchResourceFilters - returns the custom watch filter config
   590  func (c *CentralConfiguration) GetWatchResourceFilters() []ResourceFilter {
   591  	if c.WatchResourceFilters == nil {
   592  		c.WatchResourceFilters = make([]ResourceFilter, 0)
   593  	}
   594  	return c.WatchResourceFilters
   595  }
   596  
   597  // SetWatchResourceFilters - sets the custom watch filter config
   598  func (c *CentralConfiguration) SetWatchResourceFilters(filters []ResourceFilter) error {
   599  	c.WatchResourceFilters = make([]ResourceFilter, 0)
   600  	for _, filter := range filters {
   601  		if filter.Group == "" || filter.Kind == "" {
   602  			return errors.New("invalid watch filter configuration, group and kind are required")
   603  		}
   604  
   605  		if filter.Name == "" {
   606  			filter.Name = "*"
   607  		}
   608  		if len(filter.EventTypes) == 0 {
   609  			filter.EventTypes = []ResourceEventType{ResourceEventCreated, ResourceEventUpdated, ResourceEventDeleted}
   610  		}
   611  
   612  		if filter.Scope == nil {
   613  			filter.Scope = &ResourceScope{
   614  				Kind: mv1.EnvironmentGVK().Kind,
   615  				Name: c.GetEnvironmentName(),
   616  			}
   617  		} else {
   618  			if filter.Scope.Kind == "" || filter.Scope.Name == "" {
   619  				return errors.New("invalid watch filter configuration, scope kind and name are required")
   620  			}
   621  		}
   622  
   623  		c.WatchResourceFilters = append(c.WatchResourceFilters, filter)
   624  	}
   625  
   626  	return nil
   627  }
   628  
   629  const (
   630  	pathRegion                    = "central.region"
   631  	pathTenantID                  = "central.organizationID"
   632  	pathURL                       = "central.url"
   633  	pathPlatformURL               = "central.platformURL"
   634  	pathAuthPrivateKey            = "central.auth.privateKey"
   635  	pathAuthPublicKey             = "central.auth.publicKey"
   636  	pathAuthKeyPassword           = "central.auth.keyPassword"
   637  	pathAuthURL                   = "central.auth.url"
   638  	pathSingleURL                 = "central.singleURL"
   639  	pathAuthRealm                 = "central.auth.realm"
   640  	pathAuthClientID              = "central.auth.clientId"
   641  	pathAuthTimeout               = "central.auth.timeout"
   642  	pathSSLNextProtos             = "central.ssl.nextProtos"
   643  	pathSSLInsecureSkipVerify     = "central.ssl.insecureSkipVerify"
   644  	pathSSLCipherSuites           = "central.ssl.cipherSuites"
   645  	pathSSLMinVersion             = "central.ssl.minVersion"
   646  	pathSSLMaxVersion             = "central.ssl.maxVersion"
   647  	pathEnvironment               = "central.environment"
   648  	pathEnvironmentID             = "central.environmentID"
   649  	pathAgentName                 = "central.agentName"
   650  	pathDeployment                = "central.deployment"
   651  	pathMode                      = "central.mode"
   652  	pathTeam                      = "central.team"
   653  	pathPollInterval              = "central.pollInterval"
   654  	pathReportActivityFrequency   = "central.reportActivityFrequency"
   655  	pathClientTimeout             = "central.clientTimeout"
   656  	pathPageSize                  = "central.pageSize"
   657  	pathAPIServiceRevisionPattern = "central.apiServiceRevisionPattern"
   658  	pathProxyURL                  = "central.proxyUrl"
   659  	pathAPIServerVersion          = "central.apiServerVersion"
   660  	pathAdditionalTags            = "central.additionalTags"
   661  	pathAppendEnvironmentToTitle  = "central.appendEnvironmentToTitle"
   662  	pathAPIValidationCronSchedule = "central.apiValidationCronSchedule"
   663  	pathJobTimeout                = "central.jobTimeout"
   664  	pathGRPCEnabled               = "central.grpc.enabled"
   665  	pathGRPCHost                  = "central.grpc.host"
   666  	pathGRPCPort                  = "central.grpc.port"
   667  	pathGRPCInsecure              = "central.grpc.insecure"
   668  	pathCacheStoragePath          = "central.cacheStoragePath"
   669  	pathCacheStorageInterval      = "central.cacheStorageInterval"
   670  	pathCredentialsOAuthMethods   = "central.credentials.oauthMethods"
   671  )
   672  
   673  // ValidateCfg - Validates the config, implementing IConfigInterface
   674  func (c *CentralConfiguration) ValidateCfg() (err error) {
   675  	exception.Block{
   676  		Try: func() {
   677  			if supportsTraceability(c.AgentType) && c.GetUsageReportingConfig().IsOfflineMode() {
   678  				// only validate certain things when a traceability agent is in offline mode
   679  				c.validateOfflineConfig()
   680  				c.GetUsageReportingConfig().Validate()
   681  				return
   682  			}
   683  			c.validateConfig()
   684  			c.Auth.validate()
   685  
   686  			// Check that platform service account is used with market place provisioning
   687  			if strings.HasPrefix(c.Auth.GetClientID(), "DOSA_") {
   688  				exception.Throw(ErrServiceAccount)
   689  			}
   690  
   691  			if supportsTraceability(c.AgentType) {
   692  				c.GetMetricReportingConfig().Validate()
   693  				c.GetUsageReportingConfig().Validate()
   694  			}
   695  		},
   696  		Catch: func(e error) {
   697  			err = e
   698  		},
   699  	}.Do()
   700  
   701  	return
   702  }
   703  
   704  func (c *CentralConfiguration) validateConfig() {
   705  	if c.GetTenantID() == "" {
   706  		exception.Throw(ErrBadConfig.FormatError(pathTenantID))
   707  	}
   708  
   709  	c.validateURL(c.GetURL(), pathURL, true)
   710  
   711  	c.validateURL(c.GetPlatformURL(), pathPlatformURL, true)
   712  
   713  	if c.GetSingleURL() != "" {
   714  		c.validateURL(c.GetSingleURL(), pathSingleURL, true)
   715  	}
   716  
   717  	// proxyURL
   718  	c.validateURL(c.GetProxyURL(), pathProxyURL, false)
   719  
   720  	if supportsTraceability(c.AgentType) {
   721  		c.validateTraceabilityAgentConfig()
   722  	} else {
   723  		c.validateEnvironmentConfig()
   724  		c.validateDiscoveryAgentConfig()
   725  	}
   726  
   727  	if c.GetReportActivityFrequency() <= 0 {
   728  		exception.Throw(ErrBadConfig.FormatError(pathReportActivityFrequency))
   729  	}
   730  
   731  	cron, err := cronexpr.Parse(c.GetAPIValidationCronSchedule())
   732  	if err != nil {
   733  		exception.Throw(ErrBadConfig.FormatError(pathAPIValidationCronSchedule))
   734  	}
   735  	checks := 5
   736  	nextRuns := cron.NextN(time.Now(), uint(checks))
   737  	if len(nextRuns) != checks {
   738  		exception.Throw(ErrBadConfig.FormatError(pathAPIValidationCronSchedule))
   739  	}
   740  	for i := 1; i < checks-1; i++ {
   741  		delta := nextRuns[i].Sub(nextRuns[i-1])
   742  		if delta < time.Hour {
   743  			log.Tracef("%s must be at least 1 hour apart", pathAPIValidationCronSchedule)
   744  			exception.Throw(ErrBadConfig.FormatError(pathAPIValidationCronSchedule))
   745  		}
   746  	}
   747  
   748  	if c.GetClientTimeout() <= 0 {
   749  		exception.Throw(ErrBadConfig.FormatError(pathClientTimeout))
   750  	}
   751  	if c.GetJobExecutionTimeout() < 0 {
   752  		exception.Throw(ErrBadConfig.FormatError(pathJobTimeout))
   753  	}
   754  
   755  }
   756  
   757  func (c *CentralConfiguration) validateURL(urlString, configPath string, isURLRequired bool) {
   758  	if isURLRequired && urlString == "" {
   759  		exception.Throw(ErrBadConfig.FormatError(configPath))
   760  	}
   761  	if urlString != "" {
   762  		if _, err := url.ParseRequestURI(urlString); err != nil {
   763  			exception.Throw(ErrBadConfig.FormatError(configPath))
   764  		}
   765  	}
   766  }
   767  
   768  func (c *CentralConfiguration) validateDiscoveryAgentConfig() {
   769  	if c.GetPollInterval() <= 0 {
   770  		exception.Throw(ErrBadConfig.FormatError(pathPollInterval))
   771  	}
   772  }
   773  
   774  func (c *CentralConfiguration) validateEnvironmentConfig() {
   775  	if c.GetEnvironmentName() == "" {
   776  		exception.Throw(ErrBadConfig.FormatError(pathEnvironment))
   777  	}
   778  
   779  	if c.APIServerVersion == "" {
   780  		exception.Throw(ErrBadConfig.FormatError(pathAPIServerVersion))
   781  	}
   782  }
   783  func (c *CentralConfiguration) validateTraceabilityAgentConfig() {
   784  	if c.GetAPICDeployment() == "" {
   785  		exception.Throw(ErrBadConfig.FormatError(pathDeployment))
   786  	}
   787  	if c.GetEnvironmentName() == "" {
   788  		exception.Throw(ErrBadConfig.FormatError(pathEnvironment))
   789  	}
   790  }
   791  
   792  func (c *CentralConfiguration) validateOfflineConfig() {
   793  	// validate environment ID
   794  	c.SetEnvironmentID(c.EnvironmentID)
   795  	if c.GetEnvironmentID() == "" {
   796  		exception.Throw(ErrBadConfig.FormatError(pathEnvironmentID))
   797  	}
   798  }
   799  
   800  // AddCentralConfigProperties - Adds the command properties needed for Central Config
   801  func AddCentralConfigProperties(props properties.Properties, agentType AgentType) {
   802  	props.AddStringProperty(pathTenantID, "", "Tenant ID for the owner of the environment")
   803  	props.AddStringProperty(pathURL, "", "URL of Amplify Central")
   804  	props.AddStringProperty(pathTeam, "", "Team name for creating catalog")
   805  	props.AddStringProperty(pathPlatformURL, "", "URL of the platform")
   806  	props.AddStringProperty(pathSingleURL, "", "Alternate Connection for Agent if using static IP")
   807  	props.AddStringProperty(pathAuthPrivateKey, "/etc/private_key.pem", "Path to the private key for Amplify Central Authentication")
   808  	props.AddStringProperty(pathAuthPublicKey, "/etc/public_key", "Path to the public key for Amplify Central Authentication")
   809  	props.AddStringProperty(pathAuthKeyPassword, "", "Path to the password file required by the private key for Amplify Central Authentication")
   810  	props.AddStringProperty(pathAuthURL, "", "Amplify Central authentication URL")
   811  	props.AddStringProperty(pathAuthRealm, "Broker", "Amplify Central authentication Realm")
   812  	props.AddStringProperty(pathAuthClientID, "", "Client ID for the service account")
   813  	props.AddDurationProperty(pathAuthTimeout, 10*time.Second, "Timeout waiting for AxwayID response", properties.WithLowerLimit(10*time.Second))
   814  	// ssl properties and command flags
   815  	props.AddStringSliceProperty(pathSSLNextProtos, []string{}, "List of supported application level protocols, comma separated")
   816  	props.AddBoolProperty(pathSSLInsecureSkipVerify, false, "Controls whether a client verifies the server's certificate chain and host name")
   817  	props.AddStringSliceProperty(pathSSLCipherSuites, TLSDefaultCipherSuitesStringSlice(), "List of supported cipher suites, comma separated")
   818  	props.AddStringProperty(pathSSLMinVersion, TLSDefaultMinVersionString(), "Minimum acceptable SSL/TLS protocol version")
   819  	props.AddStringProperty(pathSSLMaxVersion, "0", "Maximum acceptable SSL/TLS protocol version")
   820  	props.AddStringProperty(pathEnvironment, "", "The Environment that the APIs will be associated with in Amplify Central")
   821  	props.AddStringProperty(pathAgentName, "", "The name of the asociated agent resource in Amplify Central")
   822  	props.AddStringProperty(pathProxyURL, "", "The Proxy URL to use for communication to Amplify Central")
   823  	props.AddDurationProperty(pathPollInterval, 60*time.Second, "The time interval at which the central will be polled for subscription processing")
   824  	props.AddDurationProperty(pathReportActivityFrequency, 5*time.Minute, "The time interval at which the agent polls for event changes for the periodic agent status updater")
   825  	props.AddStringProperty(pathAPIValidationCronSchedule, "@daily", "The cron schedule at which the agent validates API Services with the dataplane")
   826  	props.AddDurationProperty(pathClientTimeout, 60*time.Second, "The time interval at which the http client times out making HTTP requests and processing the response", properties.WithLowerLimit(15*time.Second), properties.WithUpperLimit(120*time.Second))
   827  	props.AddIntProperty(pathPageSize, 100, "The max page size the agent will use while retrieving API Server resources", properties.WithLowerLimitInt(10), properties.WithUpperLimitInt(100))
   828  	props.AddStringProperty(pathAPIServiceRevisionPattern, "", "The naming pattern for APIServiceRevision Title")
   829  	props.AddStringProperty(pathAPIServerVersion, "v1alpha1", "Version of the API Server")
   830  	props.AddDurationProperty(pathJobTimeout, 5*time.Minute, "The max time a job execution can run before being considered as failed")
   831  	// Watch stream config
   832  	props.AddBoolProperty(pathGRPCEnabled, false, "Controls whether an agent uses a gRPC connection")
   833  	props.AddStringProperty(pathGRPCHost, "", "Host name for Amplify Central gRPC connection")
   834  	props.AddIntProperty(pathGRPCPort, 0, "Port for Amplify Central gRPC connection")
   835  	props.AddBoolProperty(pathGRPCInsecure, false, "Controls whether an agent uses a gRPC connection with TLS")
   836  	props.AddStringProperty(pathCacheStoragePath, "", "The directory path where agent cache will be persisted to file")
   837  	props.AddDurationProperty(pathCacheStorageInterval, 10*time.Second, "The interval to persist agent caches to file", properties.WithLowerLimit(10*time.Second))
   838  	props.AddStringSliceProperty(pathCredentialsOAuthMethods, []string{}, "Allowed OAuth credential types")
   839  
   840  	if supportsTraceability(agentType) {
   841  		props.AddStringProperty(pathEnvironmentID, "", "Offline Usage Reporting Only. The Environment ID the usage is associated with on Amplify Central")
   842  		props.AddStringProperty(pathDeployment, "", "Amplify Central")
   843  		AddMetricReportingProperties(props)
   844  		AddUsageReportingProperties(props)
   845  	} else {
   846  		props.AddStringProperty(pathAdditionalTags, "", "Additional Tags to Add to discovered APIs when publishing to Amplify Central")
   847  		props.AddBoolProperty(pathAppendEnvironmentToTitle, true, "When true API titles and descriptions will be appended with environment name")
   848  		AddMigrationConfigProperties(props)
   849  	}
   850  }
   851  
   852  // ParseCentralConfig - Parses the Central Config values from the command line
   853  func ParseCentralConfig(props properties.Properties, agentType AgentType) (CentralConfig, error) {
   854  	region := US
   855  	regionSet := false
   856  	if r, ok := nameToRegionMap[props.StringPropertyValue(pathRegion)]; ok {
   857  		region = r
   858  		regionSet = true
   859  	}
   860  
   861  	regSet := regionalSettingsMap[region]
   862  
   863  	// check if CENTRAL_SINGLEURL is explicitly empty
   864  	_, set := os.LookupEnv("CENTRAL_SINGLEURL")
   865  
   866  	var metricReporting MetricReportingConfig
   867  	var usageReporting UsageReportingConfig
   868  	if supportsTraceability(agentType) {
   869  		metricReporting = ParseMetricReportingConfig(props)
   870  		usageReporting = ParseUsageReportingConfig(props)
   871  		if usageReporting.IsOfflineMode() {
   872  			// Check if this is offline usage reporting only
   873  			cfg := &CentralConfiguration{
   874  				AgentName:       props.StringPropertyValue(pathAgentName),
   875  				AgentType:       agentType,
   876  				UsageReporting:  usageReporting,
   877  				MetricReporting: metricReporting,
   878  			}
   879  			// only need the environment ID in offline mode
   880  			cfg.EnvironmentID = props.StringPropertyValue(pathEnvironmentID)
   881  			return cfg, nil
   882  		}
   883  	}
   884  
   885  	proxyURL := props.StringPropertyValue(pathProxyURL)
   886  
   887  	cfg := &CentralConfiguration{
   888  		AgentType:                 agentType,
   889  		RegionSettings:            regSet,
   890  		Region:                    region,
   891  		TenantID:                  props.StringPropertyValue(pathTenantID),
   892  		PollInterval:              props.DurationPropertyValue(pathPollInterval),
   893  		ReportActivityFrequency:   props.DurationPropertyValue(pathReportActivityFrequency),
   894  		APIValidationCronSchedule: props.StringPropertyValue(pathAPIValidationCronSchedule),
   895  		JobExecutionTimeout:       props.DurationPropertyValue(pathJobTimeout),
   896  		ClientTimeout:             props.DurationPropertyValue(pathClientTimeout),
   897  		PageSize:                  props.IntPropertyValue(pathPageSize),
   898  		APIServiceRevisionPattern: props.StringPropertyValue(pathAPIServiceRevisionPattern),
   899  		Environment:               props.StringPropertyValue(pathEnvironment),
   900  		TeamName:                  props.StringPropertyValue(pathTeam),
   901  		AgentName:                 props.StringPropertyValue(pathAgentName),
   902  		Auth: &AuthConfiguration{
   903  			RegionSettings: regSet,
   904  			URL:            strings.TrimRight(props.StringPropertyValue(pathAuthURL), urlCutSet),
   905  			Realm:          props.StringPropertyValue(pathAuthRealm),
   906  			ClientID:       props.StringPropertyValue(pathAuthClientID),
   907  			PrivateKey:     props.StringPropertyValue(pathAuthPrivateKey),
   908  			PublicKey:      props.StringPropertyValue(pathAuthPublicKey),
   909  			KeyPwd:         props.StringPropertyValue(pathAuthKeyPassword),
   910  			Timeout:        props.DurationPropertyValue(pathAuthTimeout),
   911  		},
   912  		TLS: &TLSConfiguration{
   913  			NextProtos:         props.StringSlicePropertyValue(pathSSLNextProtos),
   914  			InsecureSkipVerify: props.BoolPropertyValue(pathSSLInsecureSkipVerify),
   915  			CipherSuites:       NewCipherArray(props.StringSlicePropertyValue(pathSSLCipherSuites)),
   916  			MinVersion:         TLSVersionAsValue(props.StringPropertyValue(pathSSLMinVersion)),
   917  			MaxVersion:         TLSVersionAsValue(props.StringPropertyValue(pathSSLMaxVersion)),
   918  		},
   919  		ProxyURL: proxyURL,
   920  		GRPCCfg: GRPCConfig{
   921  			Enabled:  props.BoolPropertyValue(pathGRPCEnabled),
   922  			Host:     props.StringPropertyValue(pathGRPCHost),
   923  			Port:     props.IntPropertyValue(pathGRPCPort),
   924  			Insecure: props.BoolPropertyValue(pathGRPCInsecure),
   925  		},
   926  		CacheStoragePath:     props.StringPropertyValue(pathCacheStoragePath),
   927  		CacheStorageInterval: props.DurationPropertyValue(pathCacheStorageInterval),
   928  	}
   929  	cfg.URL = strings.TrimRight(props.StringPropertyValue(pathURL), urlCutSet)
   930  	cfg.SingleURL = strings.TrimRight(props.StringPropertyValue(pathSingleURL), urlCutSet)
   931  	cfg.isSingleURLSet = set
   932  	cfg.isRegionSet = regionSet
   933  	cfg.PlatformURL = strings.TrimRight(props.StringPropertyValue(pathPlatformURL), urlCutSet)
   934  	cfg.APIServerVersion = props.StringPropertyValue(pathAPIServerVersion)
   935  	cfg.APIServiceRevisionPattern = props.StringPropertyValue(pathAPIServiceRevisionPattern)
   936  	cfg.CredentialConfig = newCredentialConfig()
   937  	if supportsTraceability(agentType) {
   938  		cfg.APICDeployment = props.StringPropertyValue(pathDeployment)
   939  		cfg.UsageReporting = usageReporting
   940  		cfg.MetricReporting = metricReporting
   941  	} else {
   942  		cfg.TeamName = props.StringPropertyValue(pathTeam)
   943  		cfg.TagsToPublish = props.StringPropertyValue(pathAdditionalTags)
   944  		cfg.AppendEnvironmentToTitle = props.BoolPropertyValue(pathAppendEnvironmentToTitle)
   945  		cfg.MigrationSettings = ParseMigrationConfig(props)
   946  		cfg.CredentialConfig = newCredentialConfig()
   947  		cfg.CredentialConfig.SetAllowedOAuthMethods(props.StringSlicePropertyValue(pathCredentialsOAuthMethods))
   948  	}
   949  	if cfg.AgentName == "" && cfg.Environment != "" && agentType.ToShortString() != "" {
   950  		cfg.AgentName = cfg.Environment + "-" + agentType.ToShortString()
   951  	}
   952  	if regionSet {
   953  		regSet := regionalSettingsMap[region]
   954  		cfg.RegionSettings = regSet
   955  		authCfg, ok := cfg.Auth.(*AuthConfiguration)
   956  		if ok {
   957  			authCfg.RegionSettings = regSet
   958  			authCfg.URL = regSet.AuthURL
   959  		}
   960  
   961  		cfg.URL = regSet.CentralURL
   962  		cfg.PlatformURL = regSet.PlatformURL
   963  		cfg.APICDeployment = regSet.Deployment
   964  	}
   965  
   966  	return cfg, nil
   967  }
   968  
   969  func supportsTraceability(agentType AgentType) bool {
   970  	return agentType == TraceabilityAgent
   971  }