Merge ~ec0/juju-lint:fix-snap-and-better-errors into juju-lint:master

Proposed by James Hebden
Status: Merged
Approved by: James Troup
Approved revision: 5ae370127a4908793759c30456811af625a2a85c
Merged at revision: 0a72707edef77d9e82b20fb36199a7baf43261c1
Proposed branch: ~ec0/juju-lint:fix-snap-and-better-errors
Merge into: juju-lint:master
Diff against target: 312 lines (+78/-64)
6 files modified
jujulint/cli.py (+21/-4)
jujulint/config.py (+10/-10)
jujulint/config_default.yaml (+18/-24)
jujulint/lint.py (+26/-21)
setup.py (+2/-5)
snap/snapcraft.yaml (+1/-0)
Reviewer Review Type Date Requested Status
James Troup Pending
Review via email: mp+384624@code.launchpad.net

Commit message

Fix the snap, as it was not including the actual juju-lint library.
Also add more and better error handling around running juju-lint without a configuration file.
Support both absolute and config-relative paths for lint rules.

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
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision 0a72707edef77d9e82b20fb36199a7baf43261c1

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 a75a7c3..68e7bb2 100755
--- a/jujulint/cli.py
+++ b/jujulint/cli.py
@@ -21,8 +21,10 @@ from jujulint.config import Config
21from jujulint.lint import Linter21from jujulint.lint import Linter
22from jujulint.logging import Logger22from jujulint.logging import Logger
23from jujulint.openstack import OpenStack23from jujulint.openstack import OpenStack
24import os.path
24import pkg_resources25import pkg_resources
25import yaml26import yaml
27import sys
2628
2729
28class Cli:30class Cli:
@@ -35,9 +37,16 @@ class Cli:
35 self.config = Config()37 self.config = Config()
36 self.logger = Logger(self.config["logging"]["loglevel"].get())38 self.logger = Logger(self.config["logging"]["loglevel"].get())
37 self.version = pkg_resources.require("jujulint")[0].version39 self.version = pkg_resources.require("jujulint")[0].version
38 self.lint_rules = "{}/{}".format(40 rules_file = self.config["rules"]["file"].get()
39 self.config.config_dir(), self.config["rules"]["file"].get()41 # handle absolute path provided
40 )42 if os.path.isfile(rules_file):
43 self.lint_rules = rules_file
44 elif os.path.isfile("{}/{}".format(self.config.config_dir(), rules_file)):
45 # default to relative path
46 self.lint_rules = "{}/{}".format(self.config.config_dir(), rules_file)
47 else:
48 self.logger.error("Cloud not locate rules file {}".format(rules_file))
49 sys.exit(1)
4150
42 def startup_message(self):51 def startup_message(self):
43 """Print startup message to log."""52 """Print startup message to log."""
@@ -45,14 +54,20 @@ class Cli:
45 (54 (
46 "juju-lint version {} starting...\n"55 "juju-lint version {} starting...\n"
47 "\t* Config directory: {}\n"56 "\t* Config directory: {}\n"
57 "\t* Rules file: {}\n"
48 "\t* Log level: {}\n"58 "\t* Log level: {}\n"
49 ).format(59 ).format(
50 self.version,60 self.version,
51 self.config.config_dir(),61 self.config.config_dir(),
62 self.lint_rules,
52 self.config["logging"]["loglevel"].get(),63 self.config["logging"]["loglevel"].get(),
53 )64 )
54 )65 )
5566
67 def usage(self):
68 """Print program usage."""
69 self.config.parser.print_help()
70
56 def audit_file(self, filename, cloud_type=None):71 def audit_file(self, filename, cloud_type=None):
57 """Directly audit a YAML file."""72 """Directly audit a YAML file."""
58 self.logger.debug("Starting audit of file {}".format(filename))73 self.logger.debug("Starting audit of file {}".format(filename))
@@ -132,5 +147,7 @@ def main():
132 cli.audit_file(manual_file, cloud_type=manual_type)147 cli.audit_file(manual_file, cloud_type=manual_type)
133 else:148 else:
134 cli.audit_file(manual_file)149 cli.audit_file(manual_file)
135 else:150 elif "clouds" in cli.config:
136 cli.audit_all()151 cli.audit_all()
152 else:
153 cli.usage()
diff --git a/jujulint/config.py b/jujulint/config.py
index b4d1e1c..fb5497a 100644
--- a/jujulint/config.py
+++ b/jujulint/config.py
@@ -29,8 +29,8 @@ class Config(Configuration):
29 """Wrap the initialisation of confuse's Configuration object providing defaults for our application."""29 """Wrap the initialisation of confuse's Configuration object providing defaults for our application."""
30 super().__init__("juju-lint", __name__)30 super().__init__("juju-lint", __name__)
3131
32 parser = ArgumentParser(description="Sanity check one or more Juju models")32 self.parser = ArgumentParser(description="Sanity check one or more Juju models")
33 parser.add_argument(33 self.parser.add_argument(
34 "-l",34 "-l",
35 "--log-level",35 "--log-level",
36 type=str,36 type=str,
@@ -39,7 +39,7 @@ class Config(Configuration):
39 help="The default log level, valid options are info, warn, error or debug",39 help="The default log level, valid options are info, warn, error or debug",
40 dest="logging.loglevel",40 dest="logging.loglevel",
41 )41 )
42 parser.add_argument(42 self.parser.add_argument(
43 "-d",43 "-d",
44 "--output-dir",44 "--output-dir",
45 type=str,45 type=str,
@@ -48,7 +48,7 @@ class Config(Configuration):
48 help="The folder to use when saving gathered cloud data and lint reports.",48 help="The folder to use when saving gathered cloud data and lint reports.",
49 dest="output.folder",49 dest="output.folder",
50 )50 )
51 parser.add_argument(51 self.parser.add_argument(
52 "--dump-state",52 "--dump-state",
53 type=str,53 type=str,
54 help=(54 help=(
@@ -57,14 +57,14 @@ class Config(Configuration):
57 ),57 ),
58 dest="output.dump",58 dest="output.dump",
59 )59 )
60 parser.add_argument(60 self.parser.add_argument(
61 "-c",61 "-c",
62 "--config",62 "--config",
63 default="lint-rules.yaml",63 default="lint-rules.yaml",
64 help="File to read lint rules from. Defaults to `lint-rules.yaml`",64 help="File to read lint rules from. Defaults to `lint-rules.yaml`",
65 dest="rules.file",65 dest="rules.file",
66 )66 )
67 parser.add_argument(67 self.parser.add_argument(
68 "manual-file",68 "manual-file",
69 metavar="manual-file",69 metavar="manual-file",
70 nargs='?',70 nargs='?',
@@ -75,7 +75,7 @@ class Config(Configuration):
75 "Setting this disables collection of data from remote or local clouds configured via config.yaml."75 "Setting this disables collection of data from remote or local clouds configured via config.yaml."
76 ),76 ),
77 )77 )
78 parser.add_argument(78 self.parser.add_argument(
79 "-t",79 "-t",
80 "--cloud-type",80 "--cloud-type",
81 help=(81 help=(
@@ -83,13 +83,13 @@ class Config(Configuration):
83 ),83 ),
84 dest="manual-type",84 dest="manual-type",
85 )85 )
86 parser.add_argument(86 self.parser.add_argument(
87 "-o",87 "-o",
88 "--override-subordinate",88 "--override-subordinate",
89 dest="override.subordinate",89 dest="override.subordinate",
90 help="override lint-rules.yaml, e.g. -o canonical-livepatch:all",90 help="override lint-rules.yaml, e.g. -o canonical-livepatch:all",
91 )91 )
92 parser.add_argument(92 self.parser.add_argument(
93 "--logfile",93 "--logfile",
94 "-L",94 "-L",
95 default=None,95 default=None,
@@ -97,5 +97,5 @@ class Config(Configuration):
97 dest="logging.file",97 dest="logging.file",
98 )98 )
9999
100 args = parser.parse_args()100 args = self.parser.parse_args()
101 self.set_args(args, dots=True)101 self.set_args(args, dots=True)
diff --git a/jujulint/config_default.yaml b/jujulint/config_default.yaml
index 19cbe91..662df79 100644
--- a/jujulint/config_default.yaml
+++ b/jujulint/config_default.yaml
@@ -1,30 +1,24 @@
1---1---
2clouds:2# clouds:
3 # an example local Juju-deployed OpenStack3# an example local Juju-deployed OpenStack
4 cloud1:4# cloud1:
5 type: openstack5# type: openstack
6 access: local6# access: local
77
8 # an example remote Juju-deployed OpenStack8# an example remote Juju-deployed OpenStack
9 cloud2:9# cloud2:
10 type: openstack10# type: openstack
11 access: ssh11# access: ssh
12 host: 'ubuntu@openstack.example.fake'12# host: 'ubuntu@openstack.example.fake'
1313
14 # an exported bundle14# an example remote Juju-deployed OpenStack where
15 yamlfile:15# Juju controllers are registered under user 'juju-user
16 type: openstack16# in this example cloud, so we sudo to that user
17 access: dump17# cloud3:
18 file: 'export.yaml'18# type: openstack
1919# access: ssh
20 # an example remote Juju-deployed OpenStack where20# host: 'ubuntu@openstack2.example.fake'
21 # Juju controllers are registered under user 'juju-user21# sudo: 'juju-user'
22 # in this example cloud, so we sudo to that user
23 cloud3:
24 type: openstack
25 access: ssh
26 host: 'ubuntu@openstack2.example.fake'
27 sudo: 'juju-user'
2822
29logging:23logging:
30 level: INFO24 level: INFO
diff --git a/jujulint/lint.py b/jujulint/lint.py
index 92e56d6..a132541 100755
--- a/jujulint/lint.py
+++ b/jujulint/lint.py
@@ -19,6 +19,7 @@
19# along with this program. If not, see <http://www.gnu.org/licenses/>.19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20"""Lint operations and rule processing engine."""20"""Lint operations and rule processing engine."""
21import collections21import collections
22import os.path
22import pprint23import pprint
23import re24import re
2425
@@ -84,30 +85,34 @@ class Linter:
8485
85 def read_rules(self):86 def read_rules(self):
86 """Read and parse rules from YAML, optionally processing provided overrides."""87 """Read and parse rules from YAML, optionally processing provided overrides."""
87 with open(self.filename, "r") as yaml_file:88 if os.path.isfile(self.filename):
88 self.lint_rules = yaml.safe_load(yaml_file)89 with open(self.filename, "r") as yaml_file:
89 if self.overrides:90 self.lint_rules = yaml.safe_load(yaml_file)
90 for override in self.overrides.split("#"):91 if self.overrides:
91 (name, where) = override.split(":")92 for override in self.overrides.split("#"):
92 self.logger.info(93 (name, where) = override.split(":")
93 "[{}] [{}/{}] Overriding {} with {}".format(94 self.logger.info(
94 self.cloud_name,95 "[{}] [{}/{}] Overriding {} with {}".format(
95 self.controller_name,96 self.cloud_name,
96 self.model_name,97 self.controller_name,
97 name,98 self.model_name,
98 where,99 name,
100 where,
101 )
99 )102 )
103 self.lint_rules["subordinates"][name] = dict(where=where)
104 self.lint_rules["known charms"] = flatten_list(self.lint_rules["known charms"])
105 self.logger.debug(
106 "[{}] [{}/{}] Lint Rules: {}".format(
107 self.cloud_name,
108 self.controller_name,
109 self.model_name,
110 pprint.pformat(self.lint_rules),
100 )111 )
101 self.lint_rules["subordinates"][name] = dict(where=where)
102 self.lint_rules["known charms"] = flatten_list(self.lint_rules["known charms"])
103 self.logger.debug(
104 "[{}] [{}/{}] Lint Rules: {}".format(
105 self.cloud_name,
106 self.controller_name,
107 self.model_name,
108 pprint.pformat(self.lint_rules),
109 )112 )
110 )113 return True
114 self.logger.error("Rules file {} does not exist.".format(self.filename))
115 return False
111116
112 def process_subordinates(self, app_d, app_name):117 def process_subordinates(self, app_d, app_name):
113 """Iterate over subordinates and run subordinate checks."""118 """Iterate over subordinates and run subordinate checks."""
diff --git a/setup.py b/setup.py
index 4190e7a..b6b3dc9 100644
--- a/setup.py
+++ b/setup.py
@@ -17,7 +17,6 @@
17# along with this program. If not, see <http://www.gnu.org/licenses/>.17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18"""Setuptools packaging metadata for juju-lint."""18"""Setuptools packaging metadata for juju-lint."""
1919
20import re
21import setuptools20import setuptools
22import warnings21import warnings
2322
@@ -28,9 +27,7 @@ with open("README.md", "r") as fh:
2827
29setuptools.setup(28setuptools.setup(
30 name="jujulint",29 name="jujulint",
31 use_scm_version={30 use_scm_version={"local_scheme": "node-and-date"},
32 "local_scheme": "node-and-date",
33 },
34 author="Canonical",31 author="Canonical",
35 author_email="juju@lists.ubuntu.com",32 author_email="juju@lists.ubuntu.com",
36 description="Linter for Juju models to compare deployments with configurable policy",33 description="Linter for Juju models to compare deployments with configurable policy",
@@ -45,7 +42,7 @@ setuptools.setup(
45 "Intended Audience :: System Administrators",42 "Intended Audience :: System Administrators",
46 ],43 ],
47 python_requires=">=3.4",44 python_requires=">=3.4",
48 py_modules=["jujulint"],45 packages=["jujulint"],
49 entry_points={"console_scripts": ["juju-lint=jujulint.cli:main"]},46 entry_points={"console_scripts": ["juju-lint=jujulint.cli:main"]},
50 setup_requires=["setuptools_scm"],47 setup_requires=["setuptools_scm"],
51)48)
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
index b8bd6da..9ec50ef 100644
--- a/snap/snapcraft.yaml
+++ b/snap/snapcraft.yaml
@@ -22,6 +22,7 @@ parts:
22 requirements:22 requirements:
23 - requirements.txt23 - requirements.txt
24 source: .24 source: .
25 source-type: git
25 override-build: |26 override-build: |
26 snapcraftctl build27 snapcraftctl build
27 echo "Version: $(python3 setup.py --version)"28 echo "Version: $(python3 setup.py --version)"

Subscribers

People subscribed via source and target branches