33import json
44import zipfile
55
6- __version__ = '0.0.3 '
6+ __version__ = '0.1.0 '
77
88DEFAULT_PACKER_PATH = 'packer'
99
1010
11- class Packer ():
12- """Packer interface using the `sh` module (http://amoffat.github.io/sh/)
11+ class Packer (object ):
12+ """A packer client.
1313 """
14+
1415 def __init__ (self , packerfile , exc = None , only = None , vars = None ,
1516 var_file = None , exec_path = DEFAULT_PACKER_PATH ):
1617 """
1718 :param string packerfile: Path to Packer template file
1819 :param list exc: List of builders to exclude
1920 :param list only: List of builders to include
20- :param dict vars: Key Value pairs of template variables
21+ :param dict vars: key=value pairs of template variables
2122 :param string var_file: Path to variables file
2223 :param string exec_path: Path to Packer executable
2324 """
@@ -26,34 +27,39 @@ def __init__(self, packerfile, exc=None, only=None, vars=None,
2627 if not os .path .isfile (self .packerfile ):
2728 raise OSError ('packerfile not found at path: {0}' .format (
2829 self .packerfile ))
29- self .exc = self ._validate_argtype (exc if exc else [], list )
30- self .only = self ._validate_argtype (only if only else [], list )
31- self .vars = self ._validate_argtype (vars if vars else {}, dict )
30+ self .exc = self ._validate_argtype (exc or [], list )
31+ self .only = self ._validate_argtype (only or [], list )
32+ self .vars = self ._validate_argtype (vars or {}, dict )
33+
3234 self .packer = sh .Command (exec_path )
3335
3436 def build (self , parallel = True , debug = False , force = False ):
35- """Executes a Packer build ( `packer build`)
37+ """Executes a `packer build`
3638
3739 :param bool parallel: Run builders in parallel
3840 :param bool debug: Run in debug mode
3941 :param bool force: Force artifact output even if exists
4042 """
41- self .ccmd = self .packer .build
43+ self .packer_cmd = self .packer .build
44+
4245 self ._add_opt ('-parallel=true' if parallel else None )
4346 self ._add_opt ('-debug' if debug else None )
4447 self ._add_opt ('-force' if force else None )
4548 self ._append_base_arguments ()
4649 self ._add_opt (self .packerfile )
47- return self .ccmd ()
50+
51+ return self .packer_cmd ()
4852
4953 def fix (self , to_file = None ):
5054 """Implements the `packer fix` function
5155
5256 :param string to_file: File to output fixed template to
5357 """
54- self .ccmd = self .packer .fix
58+ self .packer_cmd = self .packer .fix
59+
5560 self ._add_opt (self .packerfile )
56- result = self .ccmd ()
61+
62+ result = self .packer_cmd ()
5763 if to_file :
5864 with open (to_file , 'w' ) as f :
5965 f .write (result .stdout )
@@ -87,27 +93,33 @@ def inspect(self, mrf=True):
8793 "name": "amazon"
8894 }
8995 ]
96+
9097 :param bool mrf: output in machine-readable form.
9198 """
92- self .ccmd = self .packer .inspect
99+ self .packer_cmd = self .packer .inspect
100+
93101 self ._add_opt ('-machine-readable' if mrf else None )
94102 self ._add_opt (self .packerfile )
95- result = self .ccmd ()
103+
104+ result = self .packer_cmd ()
96105 if mrf :
97- result .parsed_output = self ._parse_inspection_output (
98- result .stdout )
106+ result .parsed_output = self ._parse_inspection_output (result .stdout )
107+ else :
108+ result .parsed_output = None
99109 return result
100110
101111 def push (self , create = True , token = False ):
102112 """Implmenets the `packer push` function
103113
104114 UNTESTED! Must be used alongside an Atlas account
105115 """
106- self .ccmd = self .packer .push
116+ self .packer_cmd = self .packer .push
117+
107118 self ._add_opt ('-create=true' if create else None )
108119 self ._add_opt ('-tokn={0}' .format (token ) if token else None )
109120 self ._add_opt (self .packerfile )
110- return self .ccmd ()
121+
122+ return self .packer_cmd ()
111123
112124 def validate (self , syntax_only = False ):
113125 """Validates a Packer Template file (`packer validate`)
@@ -116,16 +128,18 @@ def validate(self, syntax_only=False):
116128 :param bool syntax_only: Whether to validate the syntax only
117129 without validating the configuration itself.
118130 """
119- self .ccmd = self .packer .validate
131+ self .packer_cmd = self .packer .validate
132+
120133 self ._add_opt ('-syntax-only' if syntax_only else None )
121134 self ._append_base_arguments ()
122135 self ._add_opt (self .packerfile )
136+
123137 # as sh raises an exception rather than return a value when execution
124138 # fails we create an object to return the exception and the validation
125139 # state
126140 try :
127- validation = self .ccmd ()
128- validation .succeeded = True if validation .exit_code == 0 else False
141+ validation = self .packer_cmd ()
142+ validation .succeeded = validation .exit_code == 0
129143 validation .error = None
130144 except Exception as ex :
131145 validation = ValidationObject ()
@@ -146,7 +160,7 @@ def version(self):
146160
147161 def _add_opt (self , option ):
148162 if option :
149- self .ccmd = self .ccmd .bake (option )
163+ self .packer_cmd = self .packer_cmd .bake (option )
150164
151165 def _validate_argtype (self , arg , argtype ):
152166 if not isinstance (arg , argtype ):
@@ -164,47 +178,43 @@ def _append_base_arguments(self):
164178 if self .exc and self .only :
165179 raise PackerException ('Cannot provide both "except" and "only"' )
166180 elif self .exc :
167- self ._add_opt ('-except={0}' .format (self ._joinc (self .exc )))
181+ self ._add_opt ('-except={0}' .format (self ._join_comma (self .exc )))
168182 elif self .only :
169- self ._add_opt ('-only={0}' .format (self ._joinc (self .only )))
183+ self ._add_opt ('-only={0}' .format (self ._join_comma (self .only )))
170184 for var , value in self .vars .items ():
171185 self ._add_opt ("-var '{0}={1}'" .format (var , value ))
172186 if self .var_file :
173187 self ._add_opt ('-var-file={0}' .format (self .var_file ))
174188
175- def _joinc (self , lst ):
189+ def _join_comma (self , lst ):
176190 """Returns a comma delimited string from a list"""
177191 return str (',' .join (lst ))
178192
179- def _joins (self , lst ):
180- """Returns a space delimited string from a list"""
181- return str (' ' .join (lst ))
182-
183193 def _parse_inspection_output (self , output ):
184194 """Parses the machine-readable output `packer inspect` provides.
185195
186196 See the inspect method for more info.
187197 This has been tested vs. Packer v0.7.5
188198 """
189199 parts = {'variables' : [], 'builders' : [], 'provisioners' : []}
190- for l in output .splitlines ():
191- l = l .split (',' )
192- if l [2 ].startswith ('template' ):
193- del l [0 :2 ]
194- component = l [0 ]
200+ for line in output .splitlines ():
201+ line = line .split (',' )
202+ if line [2 ].startswith ('template' ):
203+ del line [0 :2 ]
204+ component = line [0 ]
195205 if component == 'template-variable' :
196- variable = {"name" : l [1 ], "value" : l [2 ]}
206+ variable = {"name" : line [1 ], "value" : line [2 ]}
197207 parts ['variables' ].append (variable )
198208 elif component == 'template-builder' :
199- builder = {"name" : l [1 ], "type" : l [2 ]}
209+ builder = {"name" : line [1 ], "type" : line [2 ]}
200210 parts ['builders' ].append (builder )
201211 elif component == 'template-provisioner' :
202- provisioner = {"type" : l [1 ]}
212+ provisioner = {"type" : line [1 ]}
203213 parts ['provisioners' ].append (provisioner )
204214 return parts
205215
206216
207- class Installer ():
217+ class Installer (object ):
208218 def __init__ (self , packer_path , installer_path ):
209219 self .packer_path = packer_path
210220 self .installer_path = installer_path
@@ -215,15 +225,15 @@ def install(self):
215225 for path in zip .namelist ():
216226 zip .extract (path , self .packer_path )
217227 exec_path = os .path .join (self .packer_path , 'packer' )
218- if not self ._verify (exec_path ):
228+ if not self ._verify_packer_installed (exec_path ):
219229 raise PackerException ('packer installation failed. '
220230 'Executable could not be found under: '
221231 '{0}' .format (exec_path ))
222232 else :
223233 return exec_path
224234
225- def _verify (self , packer ):
226- return True if os .path .isfile (packer ) else False
235+ def _verify_packer_installed (self , packer_path ):
236+ return os .path .isfile (packer_path )
227237
228238
229239class ValidationObject ():
0 commit comments