Merge ~gabrielcocenza/juju-lint:bug/1980019-B into juju-lint:master

Proposed by Gabriel Cocenza
Status: Merged
Approved by: Martin Kalcok
Approved revision: cd3899ec2a0523792ae7d2e44e15b7d860d8b504
Merged at revision: 428f0c6f11ff1092806d1d09f7b11fa2c53faac4
Proposed branch: ~gabrielcocenza/juju-lint:bug/1980019-B
Merge into: juju-lint:master
Diff against target: 195 lines (+116/-9)
4 files modified
jujulint/cli.py (+30/-7)
jujulint/config.py (+2/-2)
jujulint/lint.py (+48/-0)
tests/test_jujulint.py (+36/-0)
Reviewer Review Type Date Requested Status
Martin Kalcok (community) Approve
Eric Chen Approve
Review via email: mp+427224@code.launchpad.net

Commit message

Added check for cloud_type.

- check if cloud_type passed is known.
- in case cloud_type it's not passed in the cli, it tries to detect
  by the charms in the deployment.

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
Eric Chen (eric-chen) :
review: Needs Fixing
Revision history for this message
Gabriel Cocenza (gabrielcocenza) wrote :

Thanks for your suggestions Eric.

Revision history for this message
Eric Chen (eric-chen) :
review: Approve
Revision history for this message
Martin Kalcok (martin-kalcok) wrote :

+1

review: Approve
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision 428f0c6f11ff1092806d1d09f7b11fa2c53faac4

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/jujulint/cli.py b/jujulint/cli.py
index 2d76832..97e5a34 100755
--- a/jujulint/cli.py
+++ b/jujulint/cli.py
@@ -64,17 +64,45 @@ class Cli:
64 self.logger.error("Cloud not locate rules file {}".format(rules_file))64 self.logger.error("Cloud not locate rules file {}".format(rules_file))
65 sys.exit(1)65 sys.exit(1)
6666
67 @property
68 def cloud_type(self):
69 """Get the cloud type passed in the CLI.
70
71 :return: cloud-type of the deployment or None.
72 :rtype: str
73 """
74 cloud_type = None
75 if "cloud-type" in self.config:
76 cloud_type = self.config["cloud-type"].get()
77 return cloud_type
78
79 @property
80 def manual_file(self):
81 """Get the manual file passed in the CLI.
82
83 :return: path to manual file to lint or None.
84 :rtype: str
85 """
86 manual_file = None
87 if "manual-file" in self.config:
88 manual_file = self.config["manual-file"].get()
89 return manual_file
90
67 def startup_message(self):91 def startup_message(self):
68 """Print startup message to log."""92 """Print startup message to log."""
69 self.logger.info(93 self.logger.info(
70 (94 (
71 "juju-lint version {} starting...\n"95 "juju-lint version {} starting...\n"
72 "\t* Config directory: {}\n"96 "\t* Config directory: {}\n"
97 "\t* Cloud type: {}\n"
98 "\t* Manual file: {}\n"
73 "\t* Rules file: {}\n"99 "\t* Rules file: {}\n"
74 "\t* Log level: {}\n"100 "\t* Log level: {}\n"
75 ).format(101 ).format(
76 self.version,102 self.version,
77 self.config.config_dir(),103 self.config.config_dir(),
104 self.cloud_type or "Unknown",
105 self.manual_file or False,
78 self.lint_rules,106 self.lint_rules,
79 self.config["logging"]["loglevel"].get(),107 self.config["logging"]["loglevel"].get(),
80 )108 )
@@ -161,13 +189,8 @@ def main():
161 """Program entry point."""189 """Program entry point."""
162 cli = Cli()190 cli = Cli()
163 cli.startup_message()191 cli.startup_message()
164 if "manual-file" in cli.config:192 if cli.manual_file:
165 manual_file = cli.config["manual-file"].get()193 cli.audit_file(cli.manual_file, cloud_type=cli.cloud_type)
166 if "manual-type" in cli.config:
167 manual_type = cli.config["manual-type"].get()
168 cli.audit_file(manual_file, cloud_type=manual_type)
169 else:
170 cli.audit_file(manual_file)
171 elif "clouds" in cli.config:194 elif "clouds" in cli.config:
172 cli.audit_all()195 cli.audit_all()
173 else:196 else:
diff --git a/jujulint/config.py b/jujulint/config.py
index d87677a..a4822ee 100644
--- a/jujulint/config.py
+++ b/jujulint/config.py
@@ -80,9 +80,9 @@ class Config(Configuration):
80 "-t",80 "-t",
81 "--cloud-type",81 "--cloud-type",
82 help=(82 help=(
83 "Sets the cloud type when specifying a YAML file to audit with -f or --cloud-file."83 "Sets the cloud type when specifying a YAML file to audit with -t or --cloud-type."
84 ),84 ),
85 dest="manual-type",85 dest="cloud-type",
86 )86 )
87 self.parser.add_argument(87 self.parser.add_argument(
88 "-o",88 "-o",
diff --git a/jujulint/lint.py b/jujulint/lint.py
index 4fb14bb..8f25617 100755
--- a/jujulint/lint.py
+++ b/jujulint/lint.py
@@ -720,6 +720,51 @@ class Linter:
720 }720 }
721 )721 )
722722
723 def check_cloud_type(self, deployment_charms):
724 """Check cloud_type or detect depending on the deployed charms.
725
726 :param deployment_charms: charms present in the bundle and/or status.
727 :type deployment_charms: Set
728 """
729 typical_cloud_charms = {
730 "openstack": {
731 "keystone",
732 "nova-compute",
733 "nova-cloud-controller",
734 "glance",
735 "openstack-dashboard",
736 "neutron-api",
737 },
738 "kubernetes": {
739 "kubernetes-worker",
740 "kubernetes-control-plane",
741 "containerd",
742 "calico",
743 "canal",
744 "etcd",
745 },
746 }
747 if self.cloud_type:
748 if self.cloud_type not in typical_cloud_charms.keys():
749 self._log_with_header(
750 "Cloud type {} is unknown".format(self.cloud_type),
751 level=logging.WARN,
752 )
753 return
754
755 for cloud_type, charms in typical_cloud_charms.items():
756 match = deployment_charms.intersection(charms)
757 if len(match) >= 2:
758 self._log_with_header(
759 (
760 "Setting cloud-type to '{}'. "
761 "Deployment has these charms: {} that are typically from {}."
762 ).format(cloud_type, match, cloud_type),
763 level=logging.WARN,
764 )
765 self.cloud_type = cloud_type
766 return
767
723 def check_spaces(self, parsed_yaml):768 def check_spaces(self, parsed_yaml):
724 """Check that relations end with the same endpoint."""769 """Check that relations end with the same endpoint."""
725 space_checks = self.lint_rules.get("space checks", {})770 space_checks = self.lint_rules.get("space checks", {})
@@ -1133,6 +1178,9 @@ class Linter:
1133 # Build a list of deployed charms and mapping of charms <-> applications1178 # Build a list of deployed charms and mapping of charms <-> applications
1134 self.map_charms(parsed_yaml[applications])1179 self.map_charms(parsed_yaml[applications])
11351180
1181 # Automatically detects cloud type if it's not passed as argument
1182 self.check_cloud_type(self.model.charms)
1183
1136 # Parse SAAS / remote-applications1184 # Parse SAAS / remote-applications
1137 self.parse_cmr_apps(parsed_yaml)1185 self.parse_cmr_apps(parsed_yaml)
11381186
diff --git a/tests/test_jujulint.py b/tests/test_jujulint.py
index a66c174..e99401a 100644
--- a/tests/test_jujulint.py
+++ b/tests/test_jujulint.py
@@ -119,6 +119,42 @@ class TestLinter:
119 with pytest.raises(utils.InvalidCharmNameError):119 with pytest.raises(utils.InvalidCharmNameError):
120 linter.map_charms(applications)120 linter.map_charms(applications)
121121
122 def test_check_cloud_type(self, linter, mocker):
123 """Test cloud_type detection on different scenarios."""
124 mock_log = mocker.patch("jujulint.lint.Linter._log_with_header")
125 # test models with more or equal than two matches
126 model_charms = {
127 "openstack": {"keystone", "nova-compute", "glance", "foo"},
128 "kubernetes": {"kubernetes-worker", "kubernetes-control-plane", "bar"},
129 }
130 # detect cloud_type depending on the deployment charms and
131 # if it's not passe as an argument in the cli.
132 for cloud_type, charms in model_charms.items():
133 linter.cloud_type = None
134 linter.check_cloud_type(charms)
135 assert linter.cloud_type == cloud_type
136
137 # in case cloud_type is passed doesn't change the value
138 linter.cloud_type = "openstack"
139 for cloud_type, charms in model_charms.items():
140 linter.check_cloud_type(charms)
141 assert linter.cloud_type == "openstack"
142
143 # if it's an invalid cloud_type log warn to user
144 linter.cloud_type = "foo-bar"
145 linter.check_cloud_type({"foo", "bar"})
146 mock_log.assert_called_with("Cloud type foo-bar is unknown", level=logging.WARN)
147
148 # test models with less than 2 matches without passing cloud_type in the cli
149 model_charms = {
150 "openstack": {"keystone", "foo", "bar"},
151 "kubernetes": {"foo", "bar"},
152 }
153 for cloud_type, charms in model_charms.items():
154 linter.cloud_type = None
155 linter.check_cloud_type(charms)
156 assert linter.cloud_type is None
157
122 def test_juju_status_unexpected(self, linter, juju_status):158 def test_juju_status_unexpected(self, linter, juju_status):
123 """Test that juju and workload status is expected."""159 """Test that juju and workload status is expected."""
124 # inject invalid status to the application160 # inject invalid status to the application

Subscribers

People subscribed via source and target branches