From a59a5ee6417ee57dadd294fac9a57e6875641ed6 Mon Sep 17 00:00:00 2001 From: Vahid Hashemian Date: Mon, 31 Aug 2015 15:40:46 -0700 Subject: [PATCH] Add CSAR validation and metadata extraction Add validation of CSAR files as part of translation of CSAR files. Also, add extraction of metadata from the CSAR files. Include necessary unit tests. Change-Id: I590ba71b1568a832c3b784ae99cce417a9b24f26 Partially-Implements: blueprint tosca-csar-translation --- toscaparser/prereq/__init__.py | 0 toscaparser/prereq/csar.py | 97 ++++++++++++++++ .../tests/data/CSAR/csar_hello_world.zip | Bin 0 -> 936 bytes .../data/CSAR/csar_invalid_entry_def.zip | Bin 0 -> 940 bytes .../data/CSAR/csar_metadata_not_yaml.zip | Bin 0 -> 936 bytes .../tests/data/CSAR/csar_missing_metadata.zip | Bin 0 -> 933 bytes .../tests/data/CSAR/csar_no_metadata_file.zip | Bin 0 -> 496 bytes toscaparser/tests/data/CSAR/csar_not_zip.zip | 1 + .../data/CSAR/csar_wrong_metadata_file.zip | Bin 0 -> 873 bytes toscaparser/tests/test_prereq.py | 109 ++++++++++++++++++ 10 files changed, 207 insertions(+) create mode 100644 toscaparser/prereq/__init__.py create mode 100644 toscaparser/prereq/csar.py create mode 100644 toscaparser/tests/data/CSAR/csar_hello_world.zip create mode 100644 toscaparser/tests/data/CSAR/csar_invalid_entry_def.zip create mode 100644 toscaparser/tests/data/CSAR/csar_metadata_not_yaml.zip create mode 100644 toscaparser/tests/data/CSAR/csar_missing_metadata.zip create mode 100644 toscaparser/tests/data/CSAR/csar_no_metadata_file.zip create mode 100644 toscaparser/tests/data/CSAR/csar_not_zip.zip create mode 100644 toscaparser/tests/data/CSAR/csar_wrong_metadata_file.zip create mode 100644 toscaparser/tests/test_prereq.py diff --git a/toscaparser/prereq/__init__.py b/toscaparser/prereq/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/toscaparser/prereq/csar.py b/toscaparser/prereq/csar.py new file mode 100644 index 00000000..05d53521 --- /dev/null +++ b/toscaparser/prereq/csar.py @@ -0,0 +1,97 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import os.path +import yaml +import zipfile + +from toscaparser.common.exception import ValidationError +from toscaparser.utils.gettextutils import _ + + +class CSAR(object): + + def __init__(self, csar_file): + self.csar_file = csar_file + self.is_validated = False + + def validate(self): + """Validate the provided CSAR file.""" + + self.is_validated = True + + # validate that the file exists + if not os.path.isfile(self.csar_file): + err_msg = (_('The file %s does not exist.') % self.csar_file) + raise ValidationError(message=err_msg) + + # validate that it is a valid zip file + if not zipfile.is_zipfile(self.csar_file): + err_msg = (_('The file %s is not a valid zip file.') + % self.csar_file) + raise ValidationError(message=err_msg) + + # validate that it contains the metadata file in the correct location + self.zfile = zipfile.ZipFile(self.csar_file, 'r') + filelist = self.zfile.namelist() + if 'TOSCA-Metadata/TOSCA.meta' not in filelist: + err_msg = (_('The file %s is not a valid CSAR as it does not ' + 'contain the required file "TOSCA.meta" in the ' + 'folder "TOSCA-Metadata".') % self.csar_file) + raise ValidationError(message=err_msg) + + # validate that 'Entry-Definitions' property exists in TOSCA.meta + data = self.zfile.read('TOSCA-Metadata/TOSCA.meta') + meta = yaml.load(data) + if type(meta) is not dict: + err_msg = (_('The file "TOSCA-Metadata/TOSCA.meta" in %s does not ' + 'contain valid YAML content.') % self.csar_file) + raise ValidationError(message=err_msg) + self.metadata = meta + + if 'Entry-Definitions' not in self.metadata: + err_msg = (_('The CSAR file "%s" is missing the required metadata ' + '"Entry-Definitions" in "TOSCA-Metadata/TOSCA.meta".') + % self.csar_file) + raise ValidationError(message=err_msg) + + # validate that 'Entry-Definitions' metadata value points to an + # existing file in the CSAR + entry = self.metadata['Entry-Definitions'] + if entry not in filelist: + err_msg = (_('The "Entry-Definitions" file defined in the CSAR ' + '"%s" does not exist.') % self.csar_file) + raise ValidationError(message=err_msg) + + def get_metadata(self): + """Return the metadata dictionary.""" + + # validate the csar if not already validated + if not self.is_validated: + self.validate() + + # return a copy to avoid changes overwrite the original + return dict(self.metadata) if self.metadata else None + + def _get_metadata(self, key): + if not self.is_validated: + self.validate() + return self.metadata[key] if key in self.metadata else None + + def get_author(self): + return self._get_metadata('Created-By') + + def get_version(self): + return self._get_metadata('CSAR-Version') + + def get_main_template(self): + return self._get_metadata('Entry-Definitions') diff --git a/toscaparser/tests/data/CSAR/csar_hello_world.zip b/toscaparser/tests/data/CSAR/csar_hello_world.zip new file mode 100644 index 0000000000000000000000000000000000000000..43ffbbc83003a5b4fa1e04284d080610c9051877 GIT binary patch literal 936 zcmWIWW@Zs#U|`^2XiJlK*F7Nc&47`Cp_GY%L6kv;p(MXJIWayXH76&(JijO>MXxe3 zHzzcNlYu#B!;{cU$Df3jR&X;gvb=@U(4maJG_BymW7dTLBgyp zZ{=FAG`L=N*|__n?cbPN8^e-!s(j4<|1Zgv$vT_sPOz)f!lciQonJSw?DX)lo0cK< z+S}N4vX1tI*hL!C=ah$B%sTL+~Rhv`U0$Q2YGv+BX>@%DjU(Px~E$RHs?W}X`+2pei#+94hlAU_R?AJ=h z9nHQ8jN)1wy(Y7nT%WTz?N1nw5u0P{n!SY^pQ)Z{d)V}2N%8NXZ7*4_tzP)-;`d86 zR?W|^He|&vPTHHHto>HtzSK3wJBzrLd+Hxt*;sot-uctFhV41GQzu(bS}@s4^YPEb zM6vISTk@VouX^=aV_p9=m)*O5i?5%({H@2nf2&;W&hKLk00uu7F!&i5a!cgh!3-$D z4-Ebg|6pfFUEkD_#FWI6M163;&pq)ZbTbg61w6Zt;D_>8VHErhfNTw?RIZFd3#m|`|F@NH$ z$&=&f#ZQ^MD17FO*@syf0=yZSMXxe3 zHzzcNlYu#B!;?@DF0J5ZU}Sm8%)kI9N+%u6J7mDq_P&?6Pt9MccnIw>E|)?^OAi|Nmc-E0c9L*PUQjr-ezM8#}*lVA<*6V>c~B>b1AA z>0}-439*Ybrq3x4xyp6OPDR6D+QNme7{nsB3pE<9l&_g2qo}s$%R#4p#Uvr8bDMpf zcv3A)+^ROGvIVpWU7WNxLs|Q+zWcecIB(DuIH7~(`P)d@_OrPojY@WbCAIm;|E22Wjsz|hEIz0ynJ;$ zeJ_@-+7k4koaY-)7zd-|0)axeIR!Fi$^9ICdT!9QR znt?%p;jd#o&<2bk2O5ecY>?fH8Q{q7J%MQ`a`59ao|O&cQDz|I2O7{0%#REV09pz@ A`2YX_ literal 0 HcmV?d00001 diff --git a/toscaparser/tests/data/CSAR/csar_metadata_not_yaml.zip b/toscaparser/tests/data/CSAR/csar_metadata_not_yaml.zip new file mode 100644 index 0000000000000000000000000000000000000000..3e6120bbac84a9986d2662488cd2feed3afe1bc8 GIT binary patch literal 936 zcmWIWW@Zs#U|`^2XiJlK*F7Nc&47`Cp_GY%L6kv;p(MXJIWayXH76&(JijO>MXxe3 zHzzcNlYu#B!;{d&ZBIf=E4UdLSza>`cnbIL=mavic$(J+{{aN#Qkv54(LjfN}bYbMDks_pr5(5YWBNyzEk zW*;Y>R0|Wgs?Div0j*5y8S|7G_8HENFK3;gmUMpRcGfxeZ1UL$Jl}Z2I2a`t2s}FTbXIs!$jaA~W=)$pJ(B54z?#JYlj7&hk(fVm z*5t|Y^WvvWUKBoa#_Yqa3<2JZOmfV)5}^b*Jb-DEVM`;3i6cp}LXsq!7a&IC3SfxQ z3=9Gce;wJ|4U?aQt1g4?LL66ILRyL4FnSqcWXh1VCFETIy0GTT` AZvX%Q literal 0 HcmV?d00001 diff --git a/toscaparser/tests/data/CSAR/csar_missing_metadata.zip b/toscaparser/tests/data/CSAR/csar_missing_metadata.zip new file mode 100644 index 0000000000000000000000000000000000000000..5ec7a99940dd618889839878116180f55fc12eeb GIT binary patch literal 933 zcmWIWW@Zs#U|`^2XiJlK*F7Nc&47`Cp_GY%L6kv;p(MXJIWayXH76&(JijO>MXxe3 zHzzcNlYu#B!;?@DF0J5ZU}Sm8%)kI9N+%u6J7mDq_P&?6Pt9MccnIw>E|)?^OAi|Nmc-E0c9L*PUQjr-ezM8#}*lVA<*6V>c~B>b1AA z>0}-439*Ybrq3x4xyp6OPDR6D+QNme7{nsB3pE<9l&_g2qo}s$%R#4p#Uvr8bDMpf zcv3A)+^ROGvIVpWU7WNxLs|Q+zg58> zg&PSn7A-EhKk}EAUHR&(>v^U0^cl~qyxzK6=gyqp9At3C_(2h08IO~g;gcdgFJB!` z-;1TIwgi1B=lRAH#=$7LK;Y4tr?bL?LRP+>G;7+->5)v=0w%@JnIkcO;;hM&OHB8NLJ<5}529%TkXexLyjz>LVi003V^IF0}S literal 0 HcmV?d00001 diff --git a/toscaparser/tests/data/CSAR/csar_no_metadata_file.zip b/toscaparser/tests/data/CSAR/csar_no_metadata_file.zip new file mode 100644 index 0000000000000000000000000000000000000000..b0df9b9eec2df1537f38d237687bf749f06f27f7 GIT binary patch literal 496 zcmWIWW@Zs#U|`^2XiJlK*F7Nc&47`Cp_GY%L6kv;p(MXJIWayXH76&(JijO>MXxe3 zHzzcNlYu#B!;?@DF0J5ZU}Sm8%)kI9N+%u6J7mDq_P&?6Pt9MccnIw>E|)?^OAi|Nmc-E0c9L*PUQjr-ezM8#}*lVA<*6V>c~B>b1AA z>0}-439*Ybrq3x4xyp6OPDR6D+QNme7{nsB3pE<9l&_g2qo}s$%R#4p#Uvr8bDMpf zcv3A)+^ROGvIVpWU7WNxLs|Q+zMXxe3 zHzzcNlYu#B!;?@DF0J5ZU}Sm8%)kI9N+%u6J7mDq_P&?6Pt9MccnIw>E|)?^OAi|Nmc-E0c9L*PUQjr-ezM8#}*lVA<*6V>c~B>b1AA z>0}-439*Ybrq3x4xyp6OPDR6D+QNme7{nsB3pE<9l&_g2qo}s$%R#4p#Uvr8bDMpf zcv3A)+^ROGvIVpWU7WNxLs|Q+zBs36+(E=V}5F^l_yG{p{~u_UHJU~~0A=7No6 z1RCdnX{2jjNl~S)OKMtXUS>&VeqOPa0@n1v72wUtB*%;^6-j_S1WZ&6TN*)3tY(CU zutL%lhPOaQ;|d{&(F_a%41XQ#fi_@-7tl~pc;PV=GqjN1djiu?