diff --git a/CHANGELOG.md b/CHANGELOG.md index bba5b9b4..219618e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ## [Alpha-2] +- [X] Add Zuul Log Levels to CRD - [X] Add Zuul Bootstrap Zuul Tenant Config subcommand to sfconfig cli - [X] Create ADR for sfconfig binary - [X] issue disk space metrics Matthieu Huin diff --git a/api/v1/softwarefactory_types.go b/api/v1/softwarefactory_types.go index 37488606..bea20020 100644 --- a/api/v1/softwarefactory_types.go +++ b/api/v1/softwarefactory_types.go @@ -121,6 +121,25 @@ type ZuulExecutorSpec struct { Storage StorageSpec `json:"storage,omitempty"` // How many executor pods to run Replicas int32 `json:"replicas,omitempty"` + // Specify the Log Level of the zuul-executor service. + // Valid values are: + // - "INFO" (default) + // - "WARN" + // - "DEBUG" + // Changing this value will restart the service. + // +optional + LogLevel LogLevel `json:"logLevel,omitempty"` +} + +type ZuulWebSpec struct { + // Specify the Log Level of the zuul-web launcher service. + // Valid values are: + // - "INFO" (default) + // - "WARN" + // - "DEBUG" + // Changing this value will restart the service. + // +optional + LogLevel LogLevel `json:"logLevel,omitempty"` } // Spec for the scheduler microservice @@ -129,6 +148,14 @@ type ZuulSchedulerSpec struct { Storage StorageSpec `json:"storage,omitempty"` // The address to forward statsd metrics to (optional), in the form "host:port" StatsdTarget string `json:"statsdTarget,omitempty"` + // Specify the Log Level of the zuul-scheduler service. + // Valid values are: + // - "INFO" (default) + // - "WARN" + // - "DEBUG" + // Changing this value will restart the service. + // +optional + LogLevel LogLevel `json:"logLevel,omitempty"` } // TODO: make sure to update the GetConnectionsName when adding new connection type. @@ -145,6 +172,8 @@ type ZuulSpec struct { Executor ZuulExecutorSpec `json:"executor,omitempty"` // Configuration of the scheduler microservice Scheduler ZuulSchedulerSpec `json:"scheduler,omitempty"` + // Configuration of the web microservice + Web ZuulWebSpec `json:"web,omitempty"` } func GetConnectionsName(spec *ZuulSpec) []string { diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 54f1c216..e24b6226 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -505,6 +505,7 @@ func (in *ZuulSpec) DeepCopyInto(out *ZuulSpec) { } in.Executor.DeepCopyInto(&out.Executor) in.Scheduler.DeepCopyInto(&out.Scheduler) + out.Web = in.Web } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZuulSpec. @@ -516,3 +517,18 @@ func (in *ZuulSpec) DeepCopy() *ZuulSpec { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZuulWebSpec) DeepCopyInto(out *ZuulWebSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZuulWebSpec. +func (in *ZuulWebSpec) DeepCopy() *ZuulWebSpec { + if in == nil { + return nil + } + out := new(ZuulWebSpec) + in.DeepCopyInto(out) + return out +} diff --git a/cli/run.go b/cli/run.go index d4453fd9..b43c7ea6 100644 --- a/cli/run.go +++ b/cli/run.go @@ -208,6 +208,7 @@ func EnsureCR(env *utils.ENV, sfconfig *config.SFConfig) { Puburl: "https://gerrit." + sfconfig.FQDN, }, } + cr.Spec.StorageClassName = "topolvm-provisioner" logserverVolumeSize, _ := resource.ParseQuantity("2Gi") cr.Spec.Logserver.Storage.Size = logserverVolumeSize diff --git a/config/crd/bases/sf.softwarefactory-project.io_softwarefactories.yaml b/config/crd/bases/sf.softwarefactory-project.io_softwarefactories.yaml index 854153d0..3f7d9c3e 100644 --- a/config/crd/bases/sf.softwarefactory-project.io_softwarefactories.yaml +++ b/config/crd/bases/sf.softwarefactory-project.io_softwarefactories.yaml @@ -309,6 +309,15 @@ spec: executor: description: Configuration of the executor microservices properties: + logLevel: + description: 'Specify the Log Level of the zuul-executor service. + Valid values are: - "INFO" (default) - "WARN" - "DEBUG" + Changing this value will restart the service.' + enum: + - INFO + - WARN + - DEBUG + type: string replicas: description: How many executor pods to run format: int32 @@ -461,6 +470,15 @@ spec: scheduler: description: Configuration of the scheduler microservice properties: + logLevel: + description: 'Specify the Log Level of the zuul-scheduler + service. Valid values are: - "INFO" (default) - "WARN" - + "DEBUG" Changing this value will restart the service.' + enum: + - INFO + - WARN + - DEBUG + type: string statsdTarget: description: The address to forward statsd metrics to (optional), in the form "host:port" @@ -489,6 +507,19 @@ spec: - size type: object type: object + web: + description: Configuration of the web microservice + properties: + logLevel: + description: 'Specify the Log Level of the zuul-web launcher + service. Valid values are: - "INFO" (default) - "WARN" - + "DEBUG" Changing this value will restart the service.' + enum: + - INFO + - WARN + - DEBUG + type: string + type: object type: object required: - fqdn diff --git a/controllers/static/zuul/logging.yaml.tmpl b/controllers/static/zuul/logging.yaml.tmpl new file mode 100644 index 00000000..4700ac08 --- /dev/null +++ b/controllers/static/zuul/logging.yaml.tmpl @@ -0,0 +1,37 @@ +version: 1 +formatters: + console: + class: 'zuul.lib.logutil.MultiLineFormatter' + format: '%(levelname)7s %(name)s: %(message)s' +handlers: + console: + class: logging.StreamHandler + formatter: console + level: {{.LogLevel}} + stream: ext://sys.stdout +loggers: + zuul.GerritConnection.io: + handlers: + - console + level: {{ .LogLevel }} + propagate: 0 + sqlalchemy.engine: + handlers: + - console + level: {{ .LogLevel }} + propagate: 0 + connection: + handlers: + - console + level: {{ .LogLevel }} + propagate: 0 + zuul: + handlers: + - console + level: {{ .LogLevel }} + propagate: 0 +root: + handlers: + - console + level: {{ .LogLevel }} + diff --git a/controllers/static/zuul/zuul.conf b/controllers/static/zuul/zuul.conf index 6f496da8..349e3944 100644 --- a/controllers/static/zuul/zuul.conf +++ b/controllers/static/zuul/zuul.conf @@ -9,15 +9,18 @@ tls_key=/tls/client/tls.key [scheduler] tenant_config=/var/lib/zuul/main.yaml +log_config=/var/lib/zuul/zuul-scheduler-logging.yaml [web] listen_address=0.0.0.0 +log_config=/var/lib/zuul/zuul-web-logging.yaml [executor] private_key_file=/var/lib/zuul-ssh/..data/priv # Remove /etc/pki when https://review.opendev.org/c/zuul/zuul/+/884781 is released trusted_ro_paths=/etc/pki untrusted_ro_paths=/etc/pki +log_config=/var/lib/zuul/zuul-executor-logging.yaml [auth zuul_client] driver=HS256 diff --git a/controllers/zuul.go b/controllers/zuul.go index db2dddc8..1cb544f9 100644 --- a/controllers/zuul.go +++ b/controllers/zuul.go @@ -44,6 +44,9 @@ var zuulStatsdMappingConfig string //go:embed static/zuul/generate-tenant-config.sh var zuulGenerateTenantConfig string +//go:embed static/zuul/logging.yaml.tmpl +var zuulLoggingConfig string + // Common config sections for all Zuul components var commonIniConfigSections = []string{"zookeeper", "keystore", "database"} @@ -55,6 +58,14 @@ func isStatefulset(service string) bool { return service == "zuul-scheduler" || service == "zuul-executor" || service == "zuul-merger" } +func mkZuulLoggingMount(service string) apiv1.VolumeMount { + return apiv1.VolumeMount{ + Name: "zuul-logging-config", + MountPath: "/var/lib/zuul/" + service + "-logging.yaml", + SubPath: service + "-logging.yaml", + } +} + func (r *SFController) mkZuulContainer(service string) []apiv1.Container { volumes := []apiv1.VolumeMount{ { @@ -95,8 +106,10 @@ func (r *SFController) mkZuulContainer(service string) []apiv1.Container { MountPath: "/usr/local/bin/generate-zuul-tenant-yaml.sh"}, ) envs = append(envs, r.getTenantsEnvs()...) - } + + volumes = append(volumes, mkZuulLoggingMount(service)) + command := []string{ "sh", "-c", fmt.Sprintf("exec %s -f -d", service), @@ -117,6 +130,7 @@ func mkZuulVolumes(service string) []apiv1.Volume { base.MkVolumeSecret("ca-cert"), base.MkVolumeSecret("zuul-config"), base.MkVolumeSecret("zookeeper-client-tls"), + base.MkVolumeCM("zuul-logging-config", "zuul-logging-config-map"), { Name: "zuul-ssh-key", VolumeSource: apiv1.VolumeSource{ @@ -180,6 +194,56 @@ func (r *SFController) mkInitSchedulerConfigContainer() apiv1.Container { return container } +func (r *SFController) setZuulLoggingfile() { + loggingData := make(map[string]string) + + zuulExecutorLogLevel := sfv1.InfoLogLevel + zuulSchedulerLogLevel := sfv1.InfoLogLevel + zuulWebLogLevel := sfv1.InfoLogLevel + zuulMergerLogLevel := sfv1.InfoLogLevel + + if r.cr.Spec.Zuul.Executor.LogLevel != "" { + zuulExecutorLogLevel = r.cr.Spec.Zuul.Executor.LogLevel + } + if r.cr.Spec.Zuul.Scheduler.LogLevel != "" { + zuulSchedulerLogLevel = r.cr.Spec.Zuul.Scheduler.LogLevel + } + if r.cr.Spec.Zuul.Web.LogLevel != "" { + zuulWebLogLevel = r.cr.Spec.Zuul.Web.LogLevel + } + // TODO: Uncomment when Zuul Merger is added + //if r.cr.Spec.Zuul.Merger.LogLevel != "" { + // zuulMerverLogLevel = r.cr.Spec.Zuul.Web.LogLevel + //} + + loggingData["zuul-executor-logging.yaml"], _ = utils.ParseString(zuulLoggingConfig, struct { + LogLevel string + }{string(zuulExecutorLogLevel)}) + + loggingData["zuul-scheduler-logging.yaml"], _ = utils.ParseString(zuulLoggingConfig, struct { + LogLevel string + }{string(zuulSchedulerLogLevel)}) + + loggingData["zuul-web-logging.yaml"], _ = utils.ParseString(zuulLoggingConfig, struct { + LogLevel string + }{string(zuulWebLogLevel)}) + + loggingData["zuul-merger-logging.yaml"], _ = utils.ParseString(zuulLoggingConfig, struct { + LogLevel string + }{string(zuulMergerLogLevel)}) + + r.EnsureConfigMap("zuul-logging", loggingData) + +} + +func (r *SFController) getZuulLoggingString(service string) string { + var loggingcm apiv1.ConfigMap + if !r.GetM("zuul-logging-config-map", &loggingcm) { + return "" + } + return loggingcm.Data[service+"-logging.yaml"] +} + func (r *SFController) EnsureZuulScheduler(initContainers []apiv1.Container, cfg *ini.File) bool { sections := utils.IniGetSectionNamesByPrefix(cfg, "connection") authSections := utils.IniGetSectionNamesByPrefix(cfg, "auth") @@ -193,6 +257,7 @@ func (r *SFController) EnsureZuulScheduler(initContainers []apiv1.Container, cfg "zuul-image": ZuulImage("zuul-scheduler"), "statsd_mapping": utils.Checksum([]byte(zuulStatsdMappingConfig)), "serial": "3", + "zuul-logging": utils.Checksum([]byte(r.getZuulLoggingString("zuul-scheduler"))), } if r.isConfigRepoSet() { @@ -218,6 +283,7 @@ func (r *SFController) EnsureZuulScheduler(initContainers []apiv1.Container, cfg schedulerToolingData := make(map[string]string) schedulerToolingData["generate-zuul-tenant-yaml.sh"] = zuulGenerateTenantConfig + r.EnsureConfigMap("zuul-scheduler-tooling", schedulerToolingData) zsVolumes := mkZuulVolumes("zuul-scheduler") @@ -261,6 +327,7 @@ func (r *SFController) EnsureZuulExecutor(cfg *ini.File) bool { "zuul-image": ZuulImage("zuul-executor"), "replicas": strconv.Itoa(int(r.cr.Spec.Zuul.Executor.Replicas)), "serial": "1", + "zuul-logging": utils.Checksum([]byte(r.getZuulLoggingString("zuul-executor"))), } ze := r.mkHeadlessSatefulSet("zuul-executor", "", r.getStorageConfOrDefault(r.cr.Spec.Zuul.Scheduler.Storage), int32(r.cr.Spec.Zuul.Executor.Replicas), apiv1.ReadWriteOnce) @@ -307,6 +374,7 @@ func (r *SFController) EnsureZuulWeb(cfg *ini.File) bool { "zuul-component-config": utils.IniSectionsChecksum(cfg, sections), "zuul-image": ZuulImage("zuul-web"), "serial": "1", + "zuul-logging": utils.Checksum([]byte(r.getZuulLoggingString("zuul-web"))), } zw := base.MkDeployment("zuul-web", r.ns, "") @@ -353,6 +421,7 @@ func (r *SFController) EnsureZuulComponentsFrontServices() { func (r *SFController) EnsureZuulComponents(initContainers []apiv1.Container, cfg *ini.File) bool { zuulServices := map[string]bool{} + r.setZuulLoggingfile() zuulServices["scheduler"] = r.EnsureZuulScheduler(initContainers, cfg) zuulServices["executor"] = r.EnsureZuulExecutor(cfg) zuulServices["web"] = r.EnsureZuulWeb(cfg)