From 3ddbbd1f6c70306d13db0976e1e6b3bda0c69abd Mon Sep 17 00:00:00 2001
From: sousaedu <eduardo.sousa@canonical.com>
Date: Tue, 24 Aug 2021 19:57:24 +0100
Subject: [PATCH] Adding ImagePullPolicy config option to OSM Charms

Change-Id: I04ad8444088e8a360755dc4e22b7ea53942682b2
Signed-off-by: sousaedu <eduardo.sousa@canonical.com>
---
 installers/charm/grafana/config.yaml           |  6 ++++++
 installers/charm/grafana/src/charm.py          | 17 ++++++++++++++++-
 installers/charm/kafka-exporter/config.yaml    |  6 ++++++
 installers/charm/kafka-exporter/src/charm.py   | 17 ++++++++++++++++-
 installers/charm/keystone/config.yaml          |  6 ++++++
 installers/charm/keystone/src/charm.py         | 17 ++++++++++++++++-
 installers/charm/lcm/config.yaml               |  6 ++++++
 installers/charm/lcm/src/charm.py              | 17 ++++++++++++++++-
 installers/charm/mon/config.yaml               |  6 ++++++
 installers/charm/mon/src/charm.py              | 17 ++++++++++++++++-
 installers/charm/mongodb-exporter/config.yaml  |  6 ++++++
 installers/charm/mongodb-exporter/src/charm.py | 17 ++++++++++++++++-
 installers/charm/mysqld-exporter/config.yaml   |  6 ++++++
 installers/charm/mysqld-exporter/src/charm.py  | 17 ++++++++++++++++-
 installers/charm/nbi/config.yaml               |  6 ++++++
 installers/charm/nbi/src/charm.py              | 17 ++++++++++++++++-
 installers/charm/ng-ui/config.yaml             |  6 ++++++
 installers/charm/ng-ui/src/charm.py            | 17 ++++++++++++++++-
 installers/charm/pla/config.yaml               |  6 ++++++
 installers/charm/pla/src/charm.py              | 17 ++++++++++++++++-
 installers/charm/pol/config.yaml               |  6 ++++++
 installers/charm/pol/src/charm.py              | 17 ++++++++++++++++-
 installers/charm/prometheus/config.yaml        |  6 ++++++
 installers/charm/prometheus/src/charm.py       | 17 ++++++++++++++++-
 installers/charm/ro/config.yaml                |  6 ++++++
 installers/charm/ro/src/charm.py               | 17 ++++++++++++++++-
 26 files changed, 286 insertions(+), 13 deletions(-)

diff --git a/installers/charm/grafana/config.yaml b/installers/charm/grafana/config.yaml
index 3a7e63fc..632f2120 100644
--- a/installers/charm/grafana/config.yaml
+++ b/installers/charm/grafana/config.yaml
@@ -57,3 +57,9 @@ options:
     type: boolean
     description: Enable OSM System monitoring dashboards
     default: false
+  image_pull_policy:
+    type: string
+    description: |
+      ImagePullPolicy configuration for the pod.
+      Possible values: always, ifnotpresent, never
+    default: always
diff --git a/installers/charm/grafana/src/charm.py b/installers/charm/grafana/src/charm.py
index 28be79aa..9bc612e0 100755
--- a/installers/charm/grafana/src/charm.py
+++ b/installers/charm/grafana/src/charm.py
@@ -54,6 +54,7 @@ class ConfigModel(ModelValidator):
     ingress_class: Optional[str]
     ingress_whitelist_source_range: Optional[str]
     tls_secret_name: Optional[str]
+    image_pull_policy: Optional[str]
 
     @validator("max_file_size")
     def validate_max_file_size(cls, v):
@@ -75,6 +76,18 @@ class ConfigModel(ModelValidator):
             ip_network(v)
         return v
 
+    @validator("image_pull_policy")
+    def validate_image_pull_policy(cls, v):
+        values = {
+            "always": "Always",
+            "ifnotpresent": "IfNotPresent",
+            "never": "Never",
+        }
+        v = v.lower()
+        if v not in values.keys():
+            raise ValueError("value must be always, ifnotpresent or never")
+        return values[v]
+
 
 class GrafanaCharm(CharmedOsmBase):
     """GrafanaCharm Charm."""
@@ -137,7 +150,9 @@ class GrafanaCharm(CharmedOsmBase):
         # Create Builder for the PodSpec
         pod_spec_builder = PodSpecV3Builder()
         # Build Container
-        container_builder = ContainerV3Builder(self.app.name, image_info)
+        container_builder = ContainerV3Builder(
+            self.app.name, image_info, config.image_pull_policy
+        )
         container_builder.add_port(name=self.app.name, port=PORT)
         container_builder.add_http_readiness_probe(
             "/api/health",
diff --git a/installers/charm/kafka-exporter/config.yaml b/installers/charm/kafka-exporter/config.yaml
index 706e330d..456c9c49 100644
--- a/installers/charm/kafka-exporter/config.yaml
+++ b/installers/charm/kafka-exporter/config.yaml
@@ -46,3 +46,9 @@ options:
     type: string
     description: Name of the cluster issuer for TLS certificates
     default: ""
+  image_pull_policy:
+    type: string
+    description: |
+      ImagePullPolicy configuration for the pod.
+      Possible values: always, ifnotpresent, never
+    default: always
diff --git a/installers/charm/kafka-exporter/src/charm.py b/installers/charm/kafka-exporter/src/charm.py
index a15abc84..fd24964f 100755
--- a/installers/charm/kafka-exporter/src/charm.py
+++ b/installers/charm/kafka-exporter/src/charm.py
@@ -52,6 +52,7 @@ class ConfigModel(ModelValidator):
     ingress_class: Optional[str]
     ingress_whitelist_source_range: Optional[str]
     tls_secret_name: Optional[str]
+    image_pull_policy: Optional[str]
 
     @validator("site_url")
     def validate_site_url(cls, v):
@@ -67,6 +68,18 @@ class ConfigModel(ModelValidator):
             ip_network(v)
         return v
 
+    @validator("image_pull_policy")
+    def validate_image_pull_policy(cls, v):
+        values = {
+            "always": "Always",
+            "ifnotpresent": "IfNotPresent",
+            "never": "Never",
+        }
+        v = v.lower()
+        if v not in values.keys():
+            raise ValueError("value must be always, ifnotpresent or never")
+        return values[v]
+
 
 class KafkaExporterCharm(CharmedOsmBase):
     def __init__(self, *args) -> NoReturn:
@@ -163,7 +176,9 @@ class KafkaExporterCharm(CharmedOsmBase):
         pod_spec_builder = PodSpecV3Builder()
 
         # Build container
-        container_builder = ContainerV3Builder(self.app.name, image_info)
+        container_builder = ContainerV3Builder(
+            self.app.name, image_info, config.image_pull_policy
+        )
         container_builder.add_port(name=self.app.name, port=PORT)
         container_builder.add_http_readiness_probe(
             path="/api/health",
diff --git a/installers/charm/keystone/config.yaml b/installers/charm/keystone/config.yaml
index 9a7acd5e..945ea48b 100644
--- a/installers/charm/keystone/config.yaml
+++ b/installers/charm/keystone/config.yaml
@@ -42,6 +42,12 @@ options:
     type: string
     description: Ingress URL
     default: ""
+  image_pull_policy:
+    type: string
+    description: |
+      ImagePullPolicy configuration for the pod.
+      Possible values: always, ifnotpresent, never
+    default: always
   region_id:
     type: string
     description: Region ID to be created when starting the service
diff --git a/installers/charm/keystone/src/charm.py b/installers/charm/keystone/src/charm.py
index 1dd0ba58..4e04e88a 100755
--- a/installers/charm/keystone/src/charm.py
+++ b/installers/charm/keystone/src/charm.py
@@ -84,6 +84,7 @@ class ConfigModel(ModelValidator):
     mysql_host: Optional[str]
     mysql_port: Optional[int]
     mysql_root_password: Optional[str]
+    image_pull_policy: Optional[str]
 
     @validator("max_file_size")
     def validate_max_file_size(cls, v):
@@ -111,6 +112,18 @@ class ConfigModel(ModelValidator):
             raise ValueError("Mysql port out of range")
         return v
 
+    @validator("image_pull_policy")
+    def validate_image_pull_policy(cls, v):
+        values = {
+            "always": "Always",
+            "ifnotpresent": "IfNotPresent",
+            "never": "Never",
+        }
+        v = v.lower()
+        if v not in values.keys():
+            raise ValueError("value must be always, ifnotpresent or never")
+        return values[v]
+
 
 class ConfigLdapModel(ModelValidator):
     ldap_enabled: bool
@@ -261,7 +274,9 @@ class KeystoneCharm(CharmedOsmBase):
         pod_spec_builder = PodSpecV3Builder()
 
         # Build Container
-        container_builder = ContainerV3Builder(self.app.name, image_info)
+        container_builder = ContainerV3Builder(
+            self.app.name, image_info, config.image_pull_policy
+        )
         container_builder.add_port(name=self.app.name, port=PORT)
 
         # Build files
diff --git a/installers/charm/lcm/config.yaml b/installers/charm/lcm/config.yaml
index dcebce87..27c43e5f 100644
--- a/installers/charm/lcm/config.yaml
+++ b/installers/charm/lcm/config.yaml
@@ -274,3 +274,9 @@ options:
     description: CA certificates to validate access to Helm repository
     type: string
     default: ""
+  image_pull_policy:
+    type: string
+    description: |
+      ImagePullPolicy configuration for the pod.
+      Possible values: always, ifnotpresent, never
+    default: always
diff --git a/installers/charm/lcm/src/charm.py b/installers/charm/lcm/src/charm.py
index fecd1b3c..9d7f5529 100755
--- a/installers/charm/lcm/src/charm.py
+++ b/installers/charm/lcm/src/charm.py
@@ -110,6 +110,7 @@ class ConfigModel(ModelValidator):
     vca_model_config_update_status_hook_interval: Optional[str]
     vca_stablerepourl: Optional[str]
     vca_helm_ca_certs: Optional[str]
+    image_pull_policy: Optional[str]
 
     @validator("log_level")
     def validate_log_level(cls, v):
@@ -123,6 +124,18 @@ class ConfigModel(ModelValidator):
             raise ValueError("mongodb_uri is not properly formed")
         return v
 
+    @validator("image_pull_policy")
+    def validate_image_pull_policy(cls, v):
+        values = {
+            "always": "Always",
+            "ifnotpresent": "IfNotPresent",
+            "never": "Never",
+        }
+        v = v.lower()
+        if v not in values.keys():
+            raise ValueError("value must be always, ifnotpresent or never")
+        return values[v]
+
 
 class LcmCharm(CharmedOsmBase):
     def __init__(self, *args) -> NoReturn:
@@ -167,7 +180,9 @@ class LcmCharm(CharmedOsmBase):
         pod_spec_builder = PodSpecV3Builder()
 
         # Build Container
-        container_builder = ContainerV3Builder(self.app.name, image_info)
+        container_builder = ContainerV3Builder(
+            self.app.name, image_info, config.image_pull_policy
+        )
         container_builder.add_port(name=self.app.name, port=PORT)
         container_builder.add_envs(
             {
diff --git a/installers/charm/mon/config.yaml b/installers/charm/mon/config.yaml
index d06b68df..ee593ffa 100644
--- a/installers/charm/mon/config.yaml
+++ b/installers/charm/mon/config.yaml
@@ -87,3 +87,9 @@ options:
         name: name of the file for the certificate
         content: base64 content of the certificate
       The path for the files is /certs.
+  image_pull_policy:
+    type: string
+    description: |
+      ImagePullPolicy configuration for the pod.
+      Possible values: always, ifnotpresent, never
+    default: always
diff --git a/installers/charm/mon/src/charm.py b/installers/charm/mon/src/charm.py
index 8c0a6bc7..1b7c74b6 100755
--- a/installers/charm/mon/src/charm.py
+++ b/installers/charm/mon/src/charm.py
@@ -80,6 +80,7 @@ class ConfigModel(ModelValidator):
     grafana_user: str
     grafana_password: str
     certificates: Optional[str]
+    image_pull_policy: Optional[str]
 
     @validator("log_level")
     def validate_log_level(cls, v):
@@ -99,6 +100,18 @@ class ConfigModel(ModelValidator):
             raise ValueError("mongodb_uri is not properly formed")
         return v
 
+    @validator("image_pull_policy")
+    def validate_image_pull_policy(cls, v):
+        values = {
+            "always": "Always",
+            "ifnotpresent": "IfNotPresent",
+            "never": "Never",
+        }
+        v = v.lower()
+        if v not in values.keys():
+            raise ValueError("value must be always, ifnotpresent or never")
+        return values[v]
+
     @property
     def certificates_dict(cls):
         return _extract_certificates(cls.certificates) if cls.certificates else {}
@@ -167,7 +180,9 @@ class MonCharm(CharmedOsmBase):
         pod_spec_builder = PodSpecV3Builder()
 
         # Build Container
-        container_builder = ContainerV3Builder(self.app.name, image_info)
+        container_builder = ContainerV3Builder(
+            self.app.name, image_info, config.image_pull_policy
+        )
         certs_files = self._build_cert_files(config)
 
         if certs_files:
diff --git a/installers/charm/mongodb-exporter/config.yaml b/installers/charm/mongodb-exporter/config.yaml
index 727598b9..eb19d5bc 100644
--- a/installers/charm/mongodb-exporter/config.yaml
+++ b/installers/charm/mongodb-exporter/config.yaml
@@ -49,3 +49,9 @@ options:
   mongodb_uri:
     type: string
     description: MongoDB URI (external database)
+  image_pull_policy:
+    type: string
+    description: |
+      ImagePullPolicy configuration for the pod.
+      Possible values: always, ifnotpresent, never
+    default: always
diff --git a/installers/charm/mongodb-exporter/src/charm.py b/installers/charm/mongodb-exporter/src/charm.py
index 149940a6..f4c232a9 100755
--- a/installers/charm/mongodb-exporter/src/charm.py
+++ b/installers/charm/mongodb-exporter/src/charm.py
@@ -53,6 +53,7 @@ class ConfigModel(ModelValidator):
     ingress_whitelist_source_range: Optional[str]
     tls_secret_name: Optional[str]
     mongodb_uri: Optional[str]
+    image_pull_policy: Optional[str]
 
     @validator("site_url")
     def validate_site_url(cls, v):
@@ -74,6 +75,18 @@ class ConfigModel(ModelValidator):
             raise ValueError("mongodb_uri is not properly formed")
         return v
 
+    @validator("image_pull_policy")
+    def validate_image_pull_policy(cls, v):
+        values = {
+            "always": "Always",
+            "ifnotpresent": "IfNotPresent",
+            "never": "Never",
+        }
+        v = v.lower()
+        if v not in values.keys():
+            raise ValueError("value must be always, ifnotpresent or never")
+        return values[v]
+
 
 class MongodbExporterCharm(CharmedOsmBase):
     def __init__(self, *args) -> NoReturn:
@@ -173,7 +186,9 @@ class MongodbExporterCharm(CharmedOsmBase):
         pod_spec_builder = PodSpecV3Builder()
 
         # Build container
-        container_builder = ContainerV3Builder(self.app.name, image_info)
+        container_builder = ContainerV3Builder(
+            self.app.name, image_info, config.image_pull_policy
+        )
         container_builder.add_port(name=self.app.name, port=PORT)
         container_builder.add_http_readiness_probe(
             path="/api/health",
diff --git a/installers/charm/mysqld-exporter/config.yaml b/installers/charm/mysqld-exporter/config.yaml
index a7702a3f..c25886f0 100644
--- a/installers/charm/mysqld-exporter/config.yaml
+++ b/installers/charm/mysqld-exporter/config.yaml
@@ -49,3 +49,9 @@ options:
   mysql_uri:
     type: string
     description: MySQL URI (external database)
+  image_pull_policy:
+    type: string
+    description: |
+      ImagePullPolicy configuration for the pod.
+      Possible values: always, ifnotpresent, never
+    default: always
diff --git a/installers/charm/mysqld-exporter/src/charm.py b/installers/charm/mysqld-exporter/src/charm.py
index bcd43b54..adbb5197 100755
--- a/installers/charm/mysqld-exporter/src/charm.py
+++ b/installers/charm/mysqld-exporter/src/charm.py
@@ -53,6 +53,7 @@ class ConfigModel(ModelValidator):
     ingress_whitelist_source_range: Optional[str]
     tls_secret_name: Optional[str]
     mysql_uri: Optional[str]
+    image_pull_policy: Optional[str]
 
     @validator("site_url")
     def validate_site_url(cls, v):
@@ -74,6 +75,18 @@ class ConfigModel(ModelValidator):
             raise ValueError("mysql_uri is not properly formed")
         return v
 
+    @validator("image_pull_policy")
+    def validate_image_pull_policy(cls, v):
+        values = {
+            "always": "Always",
+            "ifnotpresent": "IfNotPresent",
+            "never": "Never",
+        }
+        v = v.lower()
+        if v not in values.keys():
+            raise ValueError("value must be always, ifnotpresent or never")
+        return values[v]
+
 
 class MysqlExporterCharm(CharmedOsmBase):
     def __init__(self, *args) -> NoReturn:
@@ -173,7 +186,9 @@ class MysqlExporterCharm(CharmedOsmBase):
         pod_spec_builder = PodSpecV3Builder()
 
         # Build container
-        container_builder = ContainerV3Builder(self.app.name, image_info)
+        container_builder = ContainerV3Builder(
+            self.app.name, image_info, config.image_pull_policy
+        )
         container_builder.add_port(name=self.app.name, port=PORT)
         container_builder.add_http_readiness_probe(
             path="/api/health",
diff --git a/installers/charm/nbi/config.yaml b/installers/charm/nbi/config.yaml
index 7f327527..9c353661 100644
--- a/installers/charm/nbi/config.yaml
+++ b/installers/charm/nbi/config.yaml
@@ -72,3 +72,9 @@ options:
   mongodb_uri:
     type: string
     description: MongoDB URI (external database)
+  image_pull_policy:
+    type: string
+    description: |
+      ImagePullPolicy configuration for the pod.
+      Possible values: always, ifnotpresent, never
+    default: always
diff --git a/installers/charm/nbi/src/charm.py b/installers/charm/nbi/src/charm.py
index d3a22519..938a75a0 100755
--- a/installers/charm/nbi/src/charm.py
+++ b/installers/charm/nbi/src/charm.py
@@ -61,6 +61,7 @@ class ConfigModel(ModelValidator):
     ingress_whitelist_source_range: Optional[str]
     tls_secret_name: Optional[str]
     mongodb_uri: Optional[str]
+    image_pull_policy: Optional[str]
 
     @validator("auth_backend")
     def validate_auth_backend(cls, v):
@@ -100,6 +101,18 @@ class ConfigModel(ModelValidator):
             raise ValueError("mongodb_uri is not properly formed")
         return v
 
+    @validator("image_pull_policy")
+    def validate_image_pull_policy(cls, v):
+        values = {
+            "always": "Always",
+            "ifnotpresent": "IfNotPresent",
+            "never": "Never",
+        }
+        v = v.lower()
+        if v not in values.keys():
+            raise ValueError("value must be always, ifnotpresent or never")
+        return values[v]
+
 
 class NbiCharm(CharmedOsmBase):
     def __init__(self, *args) -> NoReturn:
@@ -180,7 +193,9 @@ class NbiCharm(CharmedOsmBase):
         )
 
         # Build Container
-        container_builder = ContainerV3Builder(self.app.name, image_info)
+        container_builder = ContainerV3Builder(
+            self.app.name, image_info, config.image_pull_policy
+        )
         container_builder.add_port(name=self.app.name, port=PORT)
         container_builder.add_tcpsocket_readiness_probe(
             PORT,
diff --git a/installers/charm/ng-ui/config.yaml b/installers/charm/ng-ui/config.yaml
index 39d3b2d9..49226b77 100644
--- a/installers/charm/ng-ui/config.yaml
+++ b/installers/charm/ng-ui/config.yaml
@@ -54,3 +54,9 @@ options:
     type: string
     description: Name of the cluster issuer for TLS certificates
     default: ""
+  image_pull_policy:
+    type: string
+    description: |
+      ImagePullPolicy configuration for the pod.
+      Possible values: always, ifnotpresent, never
+    default: always
diff --git a/installers/charm/ng-ui/src/charm.py b/installers/charm/ng-ui/src/charm.py
index 5388466e..cf0b0910 100755
--- a/installers/charm/ng-ui/src/charm.py
+++ b/installers/charm/ng-ui/src/charm.py
@@ -54,6 +54,7 @@ class ConfigModel(ModelValidator):
     ingress_class: Optional[str]
     ingress_whitelist_source_range: Optional[str]
     tls_secret_name: Optional[str]
+    image_pull_policy: Optional[str]
 
     @validator("port")
     def validate_port(cls, v):
@@ -81,6 +82,18 @@ class ConfigModel(ModelValidator):
             ip_network(v)
         return v
 
+    @validator("image_pull_policy")
+    def validate_image_pull_policy(cls, v):
+        values = {
+            "always": "Always",
+            "ifnotpresent": "IfNotPresent",
+            "never": "Never",
+        }
+        v = v.lower()
+        if v not in values.keys():
+            raise ValueError("value must be always, ifnotpresent or never")
+        return values[v]
+
 
 class NgUiCharm(CharmedOsmBase):
     def __init__(self, *args) -> NoReturn:
@@ -121,7 +134,9 @@ class NgUiCharm(CharmedOsmBase):
         # Create Builder for the PodSpec
         pod_spec_builder = PodSpecV3Builder()
         # Build Container
-        container_builder = ContainerV3Builder(self.app.name, image_info)
+        container_builder = ContainerV3Builder(
+            self.app.name, image_info, config.image_pull_policy
+        )
         container_builder.add_port(name=self.app.name, port=config.port)
         container = container_builder.build()
         container_builder.add_tcpsocket_readiness_probe(
diff --git a/installers/charm/pla/config.yaml b/installers/charm/pla/config.yaml
index 1820188a..75b19d82 100644
--- a/installers/charm/pla/config.yaml
+++ b/installers/charm/pla/config.yaml
@@ -27,3 +27,9 @@ options:
   mongodb_uri:
     type: string
     description: MongoDB URI (external database)
+  image_pull_policy:
+    type: string
+    description: |
+      ImagePullPolicy configuration for the pod.
+      Possible values: always, ifnotpresent, never
+    default: always
diff --git a/installers/charm/pla/src/charm.py b/installers/charm/pla/src/charm.py
index d9dfaa45..2a08ea59 100755
--- a/installers/charm/pla/src/charm.py
+++ b/installers/charm/pla/src/charm.py
@@ -46,6 +46,7 @@ class ConfigModel(ModelValidator):
     database_commonkey: str
     mongodb_uri: Optional[str]
     log_level: str
+    image_pull_policy: Optional[str]
 
     @validator("log_level")
     def validate_log_level(cls, v):
@@ -59,6 +60,18 @@ class ConfigModel(ModelValidator):
             raise ValueError("mongodb_uri is not properly formed")
         return v
 
+    @validator("image_pull_policy")
+    def validate_image_pull_policy(cls, v):
+        values = {
+            "always": "Always",
+            "ifnotpresent": "IfNotPresent",
+            "never": "Never",
+        }
+        v = v.lower()
+        if v not in values.keys():
+            raise ValueError("value must be always, ifnotpresent or never")
+        return values[v]
+
 
 class PlaCharm(CharmedOsmBase):
     def __init__(self, *args) -> NoReturn:
@@ -97,7 +110,9 @@ class PlaCharm(CharmedOsmBase):
         pod_spec_builder = PodSpecV3Builder()
 
         # Build Container
-        container_builder = ContainerV3Builder(self.app.name, image_info)
+        container_builder = ContainerV3Builder(
+            self.app.name, image_info, config.image_pull_policy
+        )
         container_builder.add_port(name=self.app.name, port=PORT)
         container_builder.add_envs(
             {
diff --git a/installers/charm/pol/config.yaml b/installers/charm/pol/config.yaml
index 909235e0..7b64f574 100644
--- a/installers/charm/pol/config.yaml
+++ b/installers/charm/pol/config.yaml
@@ -32,3 +32,9 @@ options:
     description: |
       Mysql URI with the following format:
         mysql://<user>:<password>@<mysql_host>:<mysql_port>/<database>
+  image_pull_policy:
+    type: string
+    description: |
+      ImagePullPolicy configuration for the pod.
+      Possible values: always, ifnotpresent, never
+    default: always
diff --git a/installers/charm/pol/src/charm.py b/installers/charm/pol/src/charm.py
index 1ad1e266..727ffbeb 100755
--- a/installers/charm/pol/src/charm.py
+++ b/installers/charm/pol/src/charm.py
@@ -49,6 +49,7 @@ class ConfigModel(ModelValidator):
     log_level: str
     mongodb_uri: Optional[str]
     mysql_uri: Optional[str]
+    image_pull_policy: Optional[str]
 
     @validator("log_level")
     def validate_log_level(cls, v):
@@ -69,6 +70,18 @@ class ConfigModel(ModelValidator):
             raise ValueError("mysql_uri is not properly formed")
         return v
 
+    @validator("image_pull_policy")
+    def validate_image_pull_policy(cls, v):
+        values = {
+            "always": "Always",
+            "ifnotpresent": "IfNotPresent",
+            "never": "Never",
+        }
+        v = v.lower()
+        if v not in values.keys():
+            raise ValueError("value must be always, ifnotpresent or never")
+        return values[v]
+
 
 class PolCharm(CharmedOsmBase):
     def __init__(self, *args) -> NoReturn:
@@ -114,7 +127,9 @@ class PolCharm(CharmedOsmBase):
         pod_spec_builder = PodSpecV3Builder()
 
         # Build Container
-        container_builder = ContainerV3Builder(self.app.name, image_info)
+        container_builder = ContainerV3Builder(
+            self.app.name, image_info, config.image_pull_policy
+        )
         container_builder.add_port(name=self.app.name, port=PORT)
         container_builder.add_envs(
             {
diff --git a/installers/charm/prometheus/config.yaml b/installers/charm/prometheus/config.yaml
index c1c0fb93..6ce1613b 100644
--- a/installers/charm/prometheus/config.yaml
+++ b/installers/charm/prometheus/config.yaml
@@ -65,3 +65,9 @@ options:
     type: boolean
     description: Boolean to enable the web admin api
     default: false
+  image_pull_policy:
+    type: string
+    description: |
+      ImagePullPolicy configuration for the pod.
+      Possible values: always, ifnotpresent, never
+    default: always
diff --git a/installers/charm/prometheus/src/charm.py b/installers/charm/prometheus/src/charm.py
index e3e0e424..3dcb5d41 100755
--- a/installers/charm/prometheus/src/charm.py
+++ b/installers/charm/prometheus/src/charm.py
@@ -60,6 +60,7 @@ class ConfigModel(ModelValidator):
     ingress_whitelist_source_range: Optional[str]
     tls_secret_name: Optional[str]
     enable_web_admin_api: bool
+    image_pull_policy: Optional[str]
 
     @validator("web_subpath")
     def validate_web_subpath(cls, v):
@@ -87,6 +88,18 @@ class ConfigModel(ModelValidator):
             ip_network(v)
         return v
 
+    @validator("image_pull_policy")
+    def validate_image_pull_policy(cls, v):
+        values = {
+            "always": "Always",
+            "ifnotpresent": "IfNotPresent",
+            "never": "Never",
+        }
+        v = v.lower()
+        if v not in values.keys():
+            raise ValueError("value must be always, ifnotpresent or never")
+        return values[v]
+
 
 class PrometheusCharm(CharmedOsmBase):
 
@@ -157,7 +170,9 @@ class PrometheusCharm(CharmedOsmBase):
         pod_spec_builder.add_container(backup_container)
 
         # Build Container
-        container_builder = ContainerV3Builder(self.app.name, image_info)
+        container_builder = ContainerV3Builder(
+            self.app.name, image_info, config.image_pull_policy
+        )
         container_builder.add_port(name=self.app.name, port=PORT)
         container_builder.add_http_readiness_probe(
             "/-/ready",
diff --git a/installers/charm/ro/config.yaml b/installers/charm/ro/config.yaml
index 0d3c9a0d..5bb0362a 100644
--- a/installers/charm/ro/config.yaml
+++ b/installers/charm/ro/config.yaml
@@ -70,3 +70,9 @@ options:
         name: name of the file for the certificate
         content: base64 content of the certificate
       The path for the files is /certs.
+  image_pull_policy:
+    type: string
+    description: |
+      ImagePullPolicy configuration for the pod.
+      Possible values: always, ifnotpresent, never
+    default: always
diff --git a/installers/charm/ro/src/charm.py b/installers/charm/ro/src/charm.py
index 951f281b..d87007e7 100755
--- a/installers/charm/ro/src/charm.py
+++ b/installers/charm/ro/src/charm.py
@@ -73,6 +73,7 @@ class ConfigModel(ModelValidator):
     ro_database: str
     openmano_tenant: str
     certificates: Optional[str]
+    image_pull_policy: Optional[str]
 
     @validator("log_level")
     def validate_log_level(cls, v):
@@ -98,6 +99,18 @@ class ConfigModel(ModelValidator):
             raise ValueError("Mysql port out of range")
         return v
 
+    @validator("image_pull_policy")
+    def validate_image_pull_policy(cls, v):
+        values = {
+            "always": "Always",
+            "ifnotpresent": "IfNotPresent",
+            "never": "Never",
+        }
+        v = v.lower()
+        if v not in values.keys():
+            raise ValueError("value must be always, ifnotpresent or never")
+        return values[v]
+
     @property
     def certificates_dict(cls):
         return _extract_certificates(cls.certificates) if cls.certificates else {}
@@ -196,7 +209,9 @@ class RoCharm(CharmedOsmBase):
         pod_spec_builder = PodSpecV3Builder()
 
         # Build Container
-        container_builder = ContainerV3Builder(self.app.name, image_info)
+        container_builder = ContainerV3Builder(
+            self.app.name, image_info, config.image_pull_policy
+        )
         certs_files = self._build_cert_files(config)
 
         if certs_files:
-- 
GitLab