2017-11-03 17:20:55 +03:00
/*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library . If not , see
* < http : //www.gnu.org/licenses/>.
*/
# include <config.h>
# include <stdlib.h>
# include "testutils.h"
2018-03-23 11:06:40 +03:00
# include "testutilsqemu.h"
# include "testutilsqemuschema.h"
2017-11-03 17:20:55 +03:00
# include "virstoragefile.h"
# include "virstring.h"
# include "virlog.h"
# include "qemu/qemu_block.h"
2018-03-23 11:06:40 +03:00
# include "qemu/qemu_qapi.h"
# include "qemu/qemu_command.h"
2017-11-03 17:20:55 +03:00
# define VIR_FROM_THIS VIR_FROM_NONE
VIR_LOG_INIT ( " tests.storagetest " ) ;
struct testBackingXMLjsonXMLdata {
int type ;
const char * xml ;
} ;
static int
testBackingXMLjsonXML ( const void * args )
{
const struct testBackingXMLjsonXMLdata * data = args ;
xmlDocPtr xml = NULL ;
xmlXPathContextPtr ctxt = NULL ;
virBuffer buf = VIR_BUFFER_INITIALIZER ;
virStorageSourcePtr xmlsrc = NULL ;
virStorageSourcePtr jsonsrc = NULL ;
virJSONValuePtr backendprops = NULL ;
virJSONValuePtr wrapper = NULL ;
char * propsstr = NULL ;
char * protocolwrapper = NULL ;
char * actualxml = NULL ;
int ret = - 1 ;
if ( VIR_ALLOC ( xmlsrc ) < 0 )
return - 1 ;
xmlsrc - > type = data - > type ;
if ( ! ( xml = virXMLParseStringCtxt ( data - > xml , " (test storage source XML) " , & ctxt ) ) )
goto cleanup ;
2017-12-12 19:55:03 +03:00
if ( virDomainDiskSourceParse ( ctxt - > node , ctxt , xmlsrc , 0 , NULL ) < 0 ) {
2017-11-03 17:20:55 +03:00
fprintf ( stderr , " failed to parse disk source xml \n " ) ;
goto cleanup ;
}
2018-03-22 18:42:47 +03:00
if ( ! ( backendprops = qemuBlockStorageSourceGetBackendProps ( xmlsrc , true ) ) ) {
2017-11-03 17:20:55 +03:00
fprintf ( stderr , " failed to format disk source json \n " ) ;
goto cleanup ;
}
2018-03-30 12:12:57 +03:00
if ( virJSONValueObjectCreate ( & wrapper , " a:file " , & backendprops , NULL ) < 0 )
2017-11-03 17:20:55 +03:00
goto cleanup ;
if ( ! ( propsstr = virJSONValueToString ( wrapper , false ) ) )
goto cleanup ;
if ( virAsprintf ( & protocolwrapper , " json:%s " , propsstr ) < 0 )
goto cleanup ;
if ( ! ( jsonsrc = virStorageSourceNewFromBackingAbsolute ( protocolwrapper ) ) ) {
fprintf ( stderr , " failed to parse disk json \n " ) ;
goto cleanup ;
}
2017-12-12 19:55:03 +03:00
if ( virDomainDiskSourceFormat ( & buf , jsonsrc , 0 , 0 , NULL ) < 0 | |
2017-11-03 17:20:55 +03:00
! ( actualxml = virBufferContentAndReset ( & buf ) ) ) {
fprintf ( stderr , " failed to format disk source xml \n " ) ;
goto cleanup ;
}
if ( STRNEQ ( actualxml , data - > xml ) ) {
fprintf ( stderr , " \n expected storage source xml: \n '%s' \n "
" actual storage source xml: \n %s \n "
" intermediate json: \n %s \n " ,
data - > xml , actualxml , protocolwrapper ) ;
goto cleanup ;
}
ret = 0 ;
cleanup :
virStorageSourceFree ( xmlsrc ) ;
virStorageSourceFree ( jsonsrc ) ;
VIR_FREE ( propsstr ) ;
VIR_FREE ( protocolwrapper ) ;
VIR_FREE ( actualxml ) ;
virJSONValueFree ( backendprops ) ;
virJSONValueFree ( wrapper ) ;
virBufferFreeAndReset ( & buf ) ;
xmlXPathFreeContext ( ctxt ) ;
xmlFreeDoc ( xml ) ;
return ret ;
}
2018-03-23 11:06:40 +03:00
struct testQemuDiskXMLToJSONData {
virQEMUDriverPtr driver ;
virHashTablePtr schema ;
virJSONValuePtr schemaroot ;
const char * name ;
bool fail ;
virJSONValuePtr * props ;
size_t nprops ;
virQEMUCapsPtr qemuCaps ;
} ;
static void
testQemuDiskXMLToPropsClear ( struct testQemuDiskXMLToJSONData * data )
{
size_t i ;
for ( i = 0 ; i < data - > nprops ; i + + )
virJSONValueFree ( data - > props [ i ] ) ;
data - > nprops = 0 ;
VIR_FREE ( data - > props ) ;
}
static const char * testQemuDiskXMLToJSONPath = abs_srcdir " /qemublocktestdata/xml2json/ " ;
static int
testQemuDiskXMLToProps ( const void * opaque )
{
struct testQemuDiskXMLToJSONData * data = ( void * ) opaque ;
virDomainDiskDefPtr disk = NULL ;
virStorageSourcePtr n ;
virJSONValuePtr props = NULL ;
char * xmlpath = NULL ;
char * xmlstr = NULL ;
int ret = - 1 ;
if ( virAsprintf ( & xmlpath , " %s%s.xml " ,
testQemuDiskXMLToJSONPath , data - > name ) < 0 )
goto cleanup ;
if ( virTestLoadFile ( xmlpath , & xmlstr ) < 0 )
goto cleanup ;
/* qemu stores node names in the status XML portion */
if ( ! ( disk = virDomainDiskDefParse ( xmlstr , NULL , data - > driver - > xmlopt ,
VIR_DOMAIN_DEF_PARSE_STATUS ) ) )
goto cleanup ;
if ( qemuCheckDiskConfig ( disk , data - > qemuCaps ) < 0 | |
qemuDomainDeviceDefValidateDisk ( disk , data - > qemuCaps ) < 0 ) {
VIR_TEST_VERBOSE ( " invalid configuration for disk \n " ) ;
goto cleanup ;
}
if ( qemuDomainPrepareDiskSourceChain ( disk , NULL , NULL , data - > qemuCaps ) < 0 )
goto cleanup ;
for ( n = disk - > src ; virStorageSourceIsBacking ( n ) ; n = n - > backingStore ) {
if ( ! ( props = qemuBlockStorageSourceGetBlockdevProps ( n ) ) ) {
if ( ! data - > fail ) {
VIR_TEST_VERBOSE ( " failed to generate qemu blockdev props \n " ) ;
goto cleanup ;
}
} else if ( data - > fail ) {
VIR_TEST_VERBOSE ( " qemu blockdev props should have failed \n " ) ;
goto cleanup ;
}
if ( VIR_APPEND_ELEMENT ( data - > props , data - > nprops , props ) < 0 )
goto cleanup ;
}
ret = 0 ;
cleanup :
virDomainDiskDefFree ( disk ) ;
VIR_FREE ( xmlpath ) ;
VIR_FREE ( xmlstr ) ;
return ret ;
}
static int
testQemuDiskXMLToPropsValidateSchema ( const void * opaque )
{
struct testQemuDiskXMLToJSONData * data = ( void * ) opaque ;
virBuffer debug = VIR_BUFFER_INITIALIZER ;
char * propsstr = NULL ;
char * debugmsg = NULL ;
int ret = 0 ;
size_t i ;
if ( data - > fail )
return EXIT_AM_SKIP ;
for ( i = 0 ; i < data - > nprops ; i + + ) {
if ( testQEMUSchemaValidate ( data - > props [ i ] , data - > schemaroot ,
data - > schema , & debug ) < 0 ) {
debugmsg = virBufferContentAndReset ( & debug ) ;
propsstr = virJSONValueToString ( data - > props [ i ] , true ) ;
VIR_TEST_VERBOSE ( " json does not conform to QAPI schema " ) ;
VIR_TEST_DEBUG ( " json: \n %s \n does not match schema. Debug output: \n %s " ,
propsstr , NULLSTR ( debugmsg ) ) ;
VIR_FREE ( debugmsg ) ;
VIR_FREE ( propsstr ) ;
ret = - 1 ;
}
virBufferFreeAndReset ( & debug ) ;
}
return ret ;
}
static int
testQemuDiskXMLToPropsValidateFile ( const void * opaque )
{
struct testQemuDiskXMLToJSONData * data = ( void * ) opaque ;
virBuffer buf = VIR_BUFFER_INITIALIZER ;
char * jsonpath = NULL ;
char * actual = NULL ;
int ret = - 1 ;
size_t i ;
if ( data - > fail )
return EXIT_AM_SKIP ;
if ( virAsprintf ( & jsonpath , " %s%s.json " ,
testQemuDiskXMLToJSONPath , data - > name ) < 0 )
goto cleanup ;
for ( i = 0 ; i < data - > nprops ; i + + ) {
char * jsonstr ;
if ( ! ( jsonstr = virJSONValueToString ( data - > props [ i ] , true ) ) )
goto cleanup ;
virBufferAdd ( & buf , jsonstr , - 1 ) ;
VIR_FREE ( jsonstr ) ;
}
if ( virBufferCheckError ( & buf ) < 0 )
goto cleanup ;
actual = virBufferContentAndReset ( & buf ) ;
ret = virTestCompareToFile ( actual , jsonpath ) ;
cleanup :
VIR_FREE ( jsonpath ) ;
VIR_FREE ( actual ) ;
return ret ;
}
2017-11-03 17:20:55 +03:00
static int
mymain ( void )
{
int ret = 0 ;
2018-03-23 11:06:40 +03:00
virQEMUDriver driver ;
2018-03-16 19:11:29 +03:00
struct testBackingXMLjsonXMLdata xmljsonxmldata ;
2018-03-23 11:06:40 +03:00
struct testQemuDiskXMLToJSONData diskxmljsondata ;
char * capslatest_x86_64 = NULL ;
virQEMUCapsPtr caps_x86_64 = NULL ;
if ( qemuTestDriverInit ( & driver ) < 0 )
return EXIT_FAILURE ;
diskxmljsondata . driver = & driver ;
if ( ! ( capslatest_x86_64 = testQemuGetLatestCapsForArch ( abs_srcdir " /qemucapabilitiesdata " ,
" x86_64 " , " xml " ) ) )
return EXIT_FAILURE ;
VIR_TEST_VERBOSE ( " \n latest caps x86_64: %s \n " , capslatest_x86_64 ) ;
if ( ! ( caps_x86_64 = qemuTestParseCapabilitiesArch ( virArchFromString ( " x86_64 " ) ,
capslatest_x86_64 ) ) )
return EXIT_FAILURE ;
diskxmljsondata . qemuCaps = caps_x86_64 ;
2017-11-03 17:20:55 +03:00
virTestCounterReset ( " qemu storage source xml->json->xml " ) ;
# define TEST_JSON_FORMAT(tpe, xmlstr) \
do { \
2018-03-16 19:11:29 +03:00
xmljsonxmldata . type = tpe ; \
xmljsonxmldata . xml = xmlstr ; \
if ( virTestRun ( virTestCounterNext ( ) , testBackingXMLjsonXML , \
& xmljsonxmldata ) < 0 ) \
2017-11-03 17:20:55 +03:00
ret = - 1 ; \
} while ( 0 )
# define TEST_JSON_FORMAT_NET(xmlstr)\
TEST_JSON_FORMAT ( VIR_STORAGE_TYPE_NETWORK , xmlstr )
TEST_JSON_FORMAT ( VIR_STORAGE_TYPE_FILE , " <source file='/path/to/file'/> \n " ) ;
/* type VIR_STORAGE_TYPE_BLOCK is not tested since it parses back to 'file' */
/* type VIR_STORAGE_TYPE_DIR it is a 'format' driver in qemu */
TEST_JSON_FORMAT_NET ( " <source protocol='http' name='file'> \n "
" <host name='example.com' port='80'/> \n "
" </source> \n " ) ;
TEST_JSON_FORMAT_NET ( " <source protocol='https' name='file'> \n "
" <host name='example.com' port='432'/> \n "
" </source> \n " ) ;
TEST_JSON_FORMAT_NET ( " <source protocol='gluster' name='vol/file'> \n "
" <host name='example.com' port='24007'/> \n "
" </source> \n " ) ;
TEST_JSON_FORMAT_NET ( " <source protocol='gluster' name='testvol/img.qcow2'> \n "
" <host name='example.com' port='1234'/> \n "
" <host transport='unix' socket='/path/socket'/> \n "
" <host name='example.com' port='24007'/> \n "
" </source> \n " ) ;
TEST_JSON_FORMAT_NET ( " <source protocol='nbd'> \n "
" <host transport='unix' socket='/path/to/socket'/> \n "
" </source> \n " ) ;
TEST_JSON_FORMAT_NET ( " <source protocol='nbd' name='blah'> \n "
" <host name='example.org' port='6000'/> \n "
" </source> \n " ) ;
TEST_JSON_FORMAT_NET ( " <source protocol='nbd'> \n "
" <host name='example.org' port='6000'/> \n "
" </source> \n " ) ;
TEST_JSON_FORMAT_NET ( " <source protocol='ssh' name='blah'> \n "
" <host name='example.org' port='6000'/> \n "
" </source> \n " ) ;
TEST_JSON_FORMAT_NET ( " <source protocol='rbd' name='libvirt/test'> \n "
" <host name='example.com' port='1234'/> \n "
" <host name='example2.com'/> \n "
" <snapshot name='snapshotname'/> \n "
" <config file='/path/to/conf'/> \n "
" </source> \n " ) ;
TEST_JSON_FORMAT_NET ( " <source protocol='iscsi' name='iqn.2016-12.com.virttest:emulated-iscsi-noauth.target/0'> \n "
" <host name='test.org' port='3260'/> \n "
" </source> \n " ) ;
TEST_JSON_FORMAT_NET ( " <source protocol='iscsi' name='iqn.2016-12.com.virttest:emulated-iscsi-noauth.target/6'> \n "
" <host name='test.org' port='1234'/> \n "
" </source> \n " ) ;
TEST_JSON_FORMAT_NET ( " <source protocol='sheepdog' name='test'> \n "
" <host name='example.com' port='321'/> \n "
" </source> \n " ) ;
TEST_JSON_FORMAT_NET ( " <source protocol='vxhs' name='c6718f6b-0401-441d-a8c3-1f0064d75ee0'> \n "
" <host name='example.com' port='9999'/> \n "
" </source> \n " ) ;
2018-03-23 11:06:40 +03:00
# define TEST_DISK_TO_JSON_FULL(nme, fl) \
do { \
diskxmljsondata . name = nme ; \
diskxmljsondata . props = NULL ; \
diskxmljsondata . nprops = 0 ; \
diskxmljsondata . fail = fl ; \
if ( virTestRun ( " disk xml to props " nme , testQemuDiskXMLToProps , \
& diskxmljsondata ) < 0 ) \
ret = - 1 ; \
if ( virTestRun ( " disk xml to props validate schema " nme , \
testQemuDiskXMLToPropsValidateSchema , & diskxmljsondata ) < 0 ) \
ret = - 1 ; \
if ( virTestRun ( " disk xml to props validate file " nme , \
testQemuDiskXMLToPropsValidateFile , & diskxmljsondata ) < 0 ) \
ret = - 1 ; \
testQemuDiskXMLToPropsClear ( & diskxmljsondata ) ; \
} while ( 0 )
# define TEST_DISK_TO_JSON(nme) TEST_DISK_TO_JSON_FULL(nme, false)
if ( ! ( diskxmljsondata . schema = testQEMUSchemaLoad ( ) ) ) {
ret = - 1 ;
goto cleanup ;
}
if ( virQEMUQAPISchemaPathGet ( " blockdev-add/arg-type " ,
diskxmljsondata . schema ,
& diskxmljsondata . schemaroot ) < 0 | |
! diskxmljsondata . schemaroot ) {
VIR_TEST_VERBOSE ( " failed to find schema entry for blockdev-add \n " ) ;
ret = - 1 ;
goto cleanup ;
}
TEST_DISK_TO_JSON_FULL ( " nodename-long-format " , true ) ;
TEST_DISK_TO_JSON_FULL ( " nodename-long-protocol " , true ) ;
cleanup :
virHashFree ( diskxmljsondata . schema ) ;
qemuTestDriverFree ( & driver ) ;
VIR_FREE ( capslatest_x86_64 ) ;
virObjectUnref ( caps_x86_64 ) ;
2017-11-03 17:20:55 +03:00
return ret = = 0 ? EXIT_SUCCESS : EXIT_FAILURE ;
}
VIR_TEST_MAIN ( mymain )