Skip to content

Commit

Permalink
[installer]: give the RepoName function access to the config
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Emms committed Apr 13, 2022
1 parent 8f10490 commit 07b95d4
Show file tree
Hide file tree
Showing 33 changed files with 148 additions and 63 deletions.
4 changes: 3 additions & 1 deletion install/installer/cmd/mirror_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ func generateMirrorList(cfgVersion string, cfg *configv1.Config) ([]mirrorListRe

images = append(images, mirrorListRepo{
Original: img,
Target: target,
Target: common.RepoName("", target, &configv1.Config{
Repository: targetRepo,
}),
})
}

Expand Down
2 changes: 1 addition & 1 deletion install/installer/pkg/common/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func InternalCAContainer(ctx *RenderContext, mod ...func(*corev1.Container)) *co
res := &corev1.Container{
Name: "update-ca-certificates",
// It's not possible to use images based on alpine due to errors running update-ca-certificates
Image: ImageName(ctx.Config.Repository, "ca-updater", ctx.VersionManifest.Components.CAUpdater.Version),
Image: ImageName(ctx.Config.Repository, "ca-updater", ctx.VersionManifest.Components.CAUpdater.Version, &ctx.Config),
ImagePullPolicy: corev1.PullIfNotPresent,
Command: []string{
"bash", "-c",
Expand Down
29 changes: 22 additions & 7 deletions install/installer/pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ func DatabaseEnv(cfg *config.Config) (res []corev1.EnvVar) {
func DatabaseWaiterContainer(ctx *RenderContext) *corev1.Container {
return &corev1.Container{
Name: "database-waiter",
Image: ImageName(ctx.Config.Repository, "service-waiter", ctx.VersionManifest.Components.ServiceWaiter.Version),
Image: ImageName(ctx.Config.Repository, "service-waiter", ctx.VersionManifest.Components.ServiceWaiter.Version, &ctx.Config),
Args: []string{
"-v",
"database",
Expand All @@ -266,7 +266,7 @@ func DatabaseWaiterContainer(ctx *RenderContext) *corev1.Container {
func MessageBusWaiterContainer(ctx *RenderContext) *corev1.Container {
return &corev1.Container{
Name: "msgbus-waiter",
Image: ImageName(ctx.Config.Repository, "service-waiter", ctx.VersionManifest.Components.ServiceWaiter.Version),
Image: ImageName(ctx.Config.Repository, "service-waiter", ctx.VersionManifest.Components.ServiceWaiter.Version, &ctx.Config),
Args: []string{
"-v",
"messagebus",
Expand All @@ -284,7 +284,7 @@ func MessageBusWaiterContainer(ctx *RenderContext) *corev1.Container {
func KubeRBACProxyContainer(ctx *RenderContext) *corev1.Container {
return &corev1.Container{
Name: "kube-rbac-proxy",
Image: ImageName(ThirdPartyContainerRepo(ctx.Config.Repository, KubeRBACProxyRepo), KubeRBACProxyImage, KubeRBACProxyTag),
Image: ImageName(ThirdPartyContainerRepo(ctx.Config.Repository, KubeRBACProxyRepo), KubeRBACProxyImage, KubeRBACProxyTag, &ctx.Config),
Args: []string{
"--v=5",
"--logtostderr",
Expand Down Expand Up @@ -339,7 +339,7 @@ func Affinity(orLabels ...string) *corev1.Affinity {
}
}

func RepoName(repo, name string) string {
func RepoName(repo, name string, cfg *config.Config) string {
var ref string
if repo == "" {
ref = name
Expand All @@ -350,11 +350,26 @@ func RepoName(repo, name string) string {
if err != nil {
panic(fmt.Sprintf("cannot parse image repo %s: %v", ref, err))
}
return pref.String()

prefString := pref.String()

if cfg.Repository != GitpodContainerRegistry {
// If not in the Gitpod registry, don't use namespaces unless specified in the config.
// This is to match the KOTS registry format of no namespace in the name
s := strings.Split(prefString, "/")

noNamespace := []string{
cfg.Repository,
s[len(s)-1],
}
return strings.Join(noNamespace, "/")
}

return prefString
}

func ImageName(repo, name, tag string) string {
ref := fmt.Sprintf("%s:%s", RepoName(repo, name), tag)
func ImageName(repo, name, tag string, cfg *config.Config) string {
ref := fmt.Sprintf("%s:%s", RepoName(repo, name, cfg), tag)
pref, err := reference.ParseNamed(ref)
if err != nil {
panic(fmt.Sprintf("cannot parse image ref %s: %v", ref, err))
Expand Down
64 changes: 62 additions & 2 deletions install/installer/pkg/common/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
package common_test

import (
"github.com/gitpod-io/gitpod/installer/pkg/common"
"testing"

"github.com/gitpod-io/gitpod/installer/pkg/common"
"github.com/gitpod-io/gitpod/installer/pkg/config/v1"

"github.com/google/go-cmp/cmp"
)

Expand All @@ -20,6 +22,7 @@ func TestRepoName(t *testing.T) {
Repo string
Name string
Expectation Expectation
CfgRepo string
}{
{
Name: "gitpod-io/workspace-full",
Expand All @@ -41,6 +44,54 @@ func TestRepoName(t *testing.T) {
Panics: true,
},
},
// Custom repo, no namespace
{
Name: "gitpod-io/workspace-full",
Expectation: Expectation{
Result: "some.registry.com/workspace-full",
},
CfgRepo: "some.registry.com",
},
{
Repo: "some-repo.com",
Name: "some-image",
Expectation: Expectation{
Result: "some.registry.com/some-image",
},
CfgRepo: "some.registry.com",
},
{
Repo: "some-repo",
Name: "not@avalid#image-name",
Expectation: Expectation{
Panics: true,
},
CfgRepo: "some.registry.com",
},
// Custom repo, namespace
{
Name: "gitpod-io/workspace-full",
Expectation: Expectation{
Result: "some.registry.com/gitpod/workspace-full",
},
CfgRepo: "some.registry.com/gitpod",
},
{
Repo: "some-repo.com",
Name: "some-image",
Expectation: Expectation{
Result: "some.registry.com/gitpod/some-image",
},
CfgRepo: "some.registry.com/gitpod",
},
{
Repo: "some-repo",
Name: "not@avalid#image-name",
Expectation: Expectation{
Panics: true,
},
CfgRepo: "some.registry.com/gitpod",
},
}

for _, test := range tests {
Expand All @@ -52,7 +103,16 @@ func TestRepoName(t *testing.T) {
act.Panics = true
}
}()
act.Result = common.RepoName(test.Repo, test.Name)
cfg := config.Config{
Repository: func() string {
if test.CfgRepo == "" {
return common.GitpodContainerRegistry
}

return test.CfgRepo
}(),
}
act.Result = common.RepoName(test.Repo, test.Name, &cfg)
}()

if diff := cmp.Diff(test.Expectation, act); diff != "" {
Expand Down
2 changes: 1 addition & 1 deletion install/installer/pkg/components/agent-smith/daemonset.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func daemonset(ctx *common.RenderContext) ([]runtime.Object, error) {
TerminationGracePeriodSeconds: pointer.Int64(30),
Containers: []corev1.Container{{
Name: Component,
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.AgentSmith.Version),
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.AgentSmith.Version, &ctx.Config),
ImagePullPolicy: corev1.PullIfNotPresent,
Args: []string{"run", "--config", "/config/config.json"},
Resources: corev1.ResourceRequirements{
Expand Down
4 changes: 2 additions & 2 deletions install/installer/pkg/components/blobserve/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
Port: ContainerPort,
Timeout: util.Duration(time.Second * 5),
Repos: map[string]blobserve.Repo{
common.RepoName(ctx.Config.Repository, ide.CodeIDEImage): {
common.RepoName(ctx.Config.Repository, ide.CodeIDEImage, &ctx.Config): {
PrePull: []string{},
Workdir: "/ide",
Replacements: []blobserve.StringReplacement{{
Expand Down Expand Up @@ -88,7 +88,7 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
Replacement: "${supervisor}",
}},
},
common.RepoName(ctx.Config.Repository, workspace.SupervisorImage): {
common.RepoName(ctx.Config.Repository, workspace.SupervisorImage, &ctx.Config): {
PrePull: []string{},
Workdir: "/.supervisor/frontend",
},
Expand Down
2 changes: 1 addition & 1 deletion install/installer/pkg/components/blobserve/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) {
Containers: []corev1.Container{{
Name: Component,
Args: []string{"run", "/mnt/config/config.json"},
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.Blobserve.Version),
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.Blobserve.Version, &ctx.Config),
ImagePullPolicy: corev1.PullIfNotPresent,
Ports: []corev1.ContainerPort{{
Name: ServicePortName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) {
}},
Containers: []corev1.Container{{
Name: Component,
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.ContentService.Version),
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.ContentService.Version, &ctx.Config),
ImagePullPolicy: corev1.PullIfNotPresent,
Args: []string{
"run",
Expand Down
2 changes: 1 addition & 1 deletion install/installer/pkg/components/dashboard/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) {
TerminationGracePeriodSeconds: pointer.Int64(30),
Containers: []corev1.Container{{
Name: Component,
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.Dashboard.Version),
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.Dashboard.Version, &ctx.Config),
ImagePullPolicy: corev1.PullIfNotPresent,
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) {
Privileged: pointer.Bool(false),
RunAsNonRoot: pointer.Bool(false),
},
Image: common.ImageName(ImageRepo, ImageName, ImageVersion),
Image: common.ImageName(ImageRepo, ImageName, ImageVersion, &ctx.Config),
Command: []string{
"/cloud_sql_proxy",
"-dir=/cloudsql",
Expand Down
9 changes: 6 additions & 3 deletions install/installer/pkg/components/database/incluster/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,15 @@ var Helm = common.CompositeHelmFunc(
helm.KeyValue("mysql.initdbScriptsConfigMap", SQLInitScripts),
helm.KeyValue("mysql.serviceAccount.name", Component),
helm.ImagePullSecrets("mysql.image.pullSecrets", cfg),
helm.KeyValue("mysql.image.registry", common.ThirdPartyContainerRepo(cfg.Config.Repository, common.DockerRegistryURL)),
helm.KeyValue("mysql.image.registry", ""),
helm.KeyValue("mysql.image.repository", common.RepoName(common.ThirdPartyContainerRepo(cfg.Config.Repository, common.DockerRegistryURL), "bitnami/mysql", &cfg.Config)),
helm.ImagePullSecrets("mysql.metrics.image.pullSecrets", cfg),
helm.KeyValue("mysql.metrics.image.registry", common.ThirdPartyContainerRepo(cfg.Config.Repository, common.DockerRegistryURL)),
helm.KeyValue("mysql.metrics.image.registry", ""),
helm.KeyValue("mysql.metrics.image.repository", common.RepoName(common.ThirdPartyContainerRepo(cfg.Config.Repository, common.DockerRegistryURL), "bitnami/mysqld-exporter", &cfg.Config)),
helm.ImagePullSecrets("mysql.volumePermissions.image.pullSecrets", cfg),
helm.KeyValue("mysql.volumePermissions.image.pullPolicy", "IfNotPresent"),
helm.KeyValue("mysql.volumePermissions.image.registry", common.ThirdPartyContainerRepo(cfg.Config.Repository, common.DockerRegistryURL)),
helm.KeyValue("mysql.volumePermissions.image.registry", ""),
helm.KeyValue("mysql.volumePermissions.image.repository", common.RepoName(common.ThirdPartyContainerRepo(cfg.Config.Repository, common.DockerRegistryURL), "bitnami/bitnami-shell", &cfg.Config)),

// improve start time
helm.KeyValue("mysql.primary.startupProbe.enabled", "false"),
Expand Down
2 changes: 1 addition & 1 deletion install/installer/pkg/components/database/init/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func job(ctx *common.RenderContext) ([]runtime.Object, error) {
InitContainers: []corev1.Container{*common.DatabaseWaiterContainer(ctx)},
Containers: []corev1.Container{{
Name: fmt.Sprintf("%s-session", Component),
Image: common.ImageName(common.ThirdPartyContainerRepo(ctx.Config.Repository, ""), dbSessionsImage, dbSessionsTag),
Image: common.ImageName(common.ThirdPartyContainerRepo(ctx.Config.Repository, ""), dbSessionsImage, dbSessionsTag, &ctx.Config),
ImagePullPolicy: corev1.PullIfNotPresent,
Env: common.MergeEnv(
common.DatabaseEnv(&ctx.Config),
Expand Down
2 changes: 1 addition & 1 deletion install/installer/pkg/components/docker-registry/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var Helm = common.CompositeHelmFunc(
return nil, err
}

repository := fmt.Sprintf("%s/library/registry", common.ThirdPartyContainerRepo(cfg.Config.Repository, common.DockerRegistryURL))
repository := common.RepoName(common.ThirdPartyContainerRepo(cfg.Config.Repository, common.DockerRegistryURL), "library/registry", &cfg.Config)

registryValues := []string{
helm.KeyValue(fmt.Sprintf("docker-registry.podAnnotations.%s", strings.Replace(common.AnnotationConfigChecksum, ".", "\\.", -1)), secretHash),
Expand Down
2 changes: 1 addition & 1 deletion install/installer/pkg/components/gitpod/cronjob.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func cronjob(ctx *common.RenderContext) ([]runtime.Object, error) {
Containers: []v1.Container{
{
Name: installationTelemetryComponent,
Image: common.ImageName(ctx.Config.Repository, "installation-telemetry", ctx.VersionManifest.Components.InstallationTelemetry.Version),
Image: common.ImageName(ctx.Config.Repository, "installation-telemetry", ctx.VersionManifest.Components.InstallationTelemetry.Version, &ctx.Config),
ImagePullPolicy: v1.PullIfNotPresent,
Args: []string{
"send",
Expand Down
2 changes: 1 addition & 1 deletion install/installer/pkg/components/ide-proxy/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) {
TerminationGracePeriodSeconds: pointer.Int64(30),
Containers: []corev1.Container{{
Name: Component,
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.IDEProxy.Version),
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.IDEProxy.Version, &ctx.Config),
ImagePullPolicy: corev1.PullIfNotPresent,
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
PullSecret: secretName,
PullSecretFile: PullSecretFile,
BaseImageRepository: fmt.Sprintf("%s/base-images", registryName),
BuilderImage: common.ImageName(ctx.Config.Repository, BuilderImage, ctx.VersionManifest.Components.ImageBuilderMk3.BuilderImage.Version),
BuilderImage: common.ImageName(ctx.Config.Repository, BuilderImage, ctx.VersionManifest.Components.ImageBuilderMk3.BuilderImage.Version, &ctx.Config),
WorkspaceImageRepository: fmt.Sprintf("%s/workspace-images", registryName),
}

Expand All @@ -58,7 +58,7 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
RefCache: config.RefCacheConfig{
Interval: util.Duration(time.Hour * 6).String(),
Refs: []string{
common.ImageName(common.ThirdPartyContainerRepo(ctx.Config.Repository, ""), workspace.DefaultWorkspaceImage, workspace.DefaultWorkspaceImageVersion),
common.ImageName(common.ThirdPartyContainerRepo(ctx.Config.Repository, ""), workspace.DefaultWorkspaceImage, workspace.DefaultWorkspaceImageVersion, &ctx.Config),
},
},
Service: config.Service{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) {
},
Containers: []corev1.Container{{
Name: Component,
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.ImageBuilderMk3.Version),
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.ImageBuilderMk3.Version, &ctx.Config),
ImagePullPolicy: corev1.PullIfNotPresent,
Args: []string{
"run",
Expand Down
2 changes: 1 addition & 1 deletion install/installer/pkg/components/migrations/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func job(ctx *common.RenderContext) ([]runtime.Object, error) {
InitContainers: []corev1.Container{*common.DatabaseWaiterContainer(ctx)},
Containers: []corev1.Container{{
Name: Component,
Image: common.ImageName(ctx.Config.Repository, "db-migrations", ctx.VersionManifest.Components.DBMigrations.Version),
Image: common.ImageName(ctx.Config.Repository, "db-migrations", ctx.VersionManifest.Components.DBMigrations.Version, &ctx.Config),
ImagePullPolicy: corev1.PullIfNotPresent,
Env: common.MergeEnv(
common.DatabaseEnv(&ctx.Config),
Expand Down
6 changes: 4 additions & 2 deletions install/installer/pkg/components/minio/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ var Helm = common.CompositeHelmFunc(
func(cfg *common.RenderContext) ([]string, error) {
commonHelmValues := []string{
helm.ImagePullSecrets("minio.image.pullSecrets", cfg),
helm.KeyValue("minio.image.registry", common.ThirdPartyContainerRepo(cfg.Config.Repository, common.DockerRegistryURL)),
helm.KeyValue("minio.image.registry", ""),
helm.KeyValue("minio.image.repository", common.RepoName(common.ThirdPartyContainerRepo(cfg.Config.Repository, common.DockerRegistryURL), "bitnami/minio", &cfg.Config)),
helm.ImagePullSecrets("minio.volumePermissions.image.pullSecrets", cfg),
helm.KeyValue("minio.volumePermissions.image.registry", common.ThirdPartyContainerRepo(cfg.Config.Repository, common.DockerRegistryURL)),
helm.KeyValue("minio.volumePermissions.image.registry", ""),
helm.KeyValue("minio.volumePermissions.image.repository", common.RepoName(common.ThirdPartyContainerRepo(cfg.Config.Repository, common.DockerRegistryURL), "bitnami/bitnami-shell", &cfg.Config)),
}

if pointer.BoolDeref(cfg.Config.ObjectStorage.InCluster, false) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func statefulset(ctx *common.RenderContext) ([]runtime.Object, error) {
}},
Containers: []v1.Container{{
Name: Component,
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.OpenVSXProxy.Version),
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.OpenVSXProxy.Version, &ctx.Config),
Args: []string{"/config/config.json"},
ReadinessProbe: &v1.Probe{
ProbeHandler: v1.ProbeHandler{
Expand Down
6 changes: 3 additions & 3 deletions install/installer/pkg/components/proxy/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) {
Volumes: volumes,
InitContainers: []corev1.Container{{
Name: "sysctl",
Image: common.ImageName(common.ThirdPartyContainerRepo(ctx.Config.Repository, common.DockerRegistryURL), InitContainerImage, InitContainerTag),
Image: common.ImageName(common.ThirdPartyContainerRepo(ctx.Config.Repository, common.DockerRegistryURL), InitContainerImage, InitContainerTag, &ctx.Config),
ImagePullPolicy: corev1.PullIfNotPresent,
SecurityContext: &corev1.SecurityContext{
Privileged: pointer.Bool(true),
Expand All @@ -143,7 +143,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) {
}},
Containers: []corev1.Container{{
Name: "kube-rbac-proxy",
Image: common.ImageName(common.ThirdPartyContainerRepo(ctx.Config.Repository, KubeRBACProxyRepo), KubeRBACProxyImage, KubeRBACProxyTag),
Image: common.ImageName(common.ThirdPartyContainerRepo(ctx.Config.Repository, KubeRBACProxyRepo), KubeRBACProxyImage, KubeRBACProxyTag, &ctx.Config),
ImagePullPolicy: corev1.PullIfNotPresent,
Args: []string{
"--v=10",
Expand Down Expand Up @@ -178,7 +178,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) {
},
}, {
Name: Component,
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.Proxy.Version),
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.Proxy.Version, &ctx.Config),
ImagePullPolicy: corev1.PullIfNotPresent,
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) {
TerminationGracePeriodSeconds: pointer.Int64(30),
Containers: []corev1.Container{{
Name: Component,
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.PublicAPIServer.Version),
Image: common.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.PublicAPIServer.Version, &ctx.Config),
ImagePullPolicy: corev1.PullIfNotPresent,
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
Expand Down
Loading

0 comments on commit 07b95d4

Please sign in to comment.