| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- #!/usr/bin/env python
- #
- # Creates .wxs files to be used to generate multiple MSI targets
- #
- # by default the script will check for dist and enterprise-dist, and parse
- # the version as needed options are provided to give a build version that will
- # download the zip, drop in to dist/enterprise-dist and do the same thing
- #
- # Expected paths and names
- # /tmp/dist/grafana-6.0.0-ca0bc2c5pre3.windows-amd64.zip
- # /tmp/enterprise-dist/grafana-enterprise-6.0.0-29b28127pre3.windows-amd64.zip
- #
- # Optionally (mainly for testing), pass arguments to pull a specific build
- # -b,--build 5.4.3
- # -e,--enterprise add this flag to specify enterprise
- # -p,--premium, add this flag to include premium plugins
- #
- # When using the build option, the zip file is created in either dist or
- # dist-enterprise according to the -e flag toggle.
- #
- # https://s3-us-west-2.amazonaws.com/grafana-releases/release/
- # grafana-{}.windows-amd64.zip
- #
- # https://dl.grafana.com/enterprise/release/
- # grafana-enterprise-{}.windows-amd64.zip
- #
- import os
- import shutil
- import argparse
- from jinja2 import Template, Environment, FileSystemLoader
- from utils import *
- #############################
- # Constants - DO NOT CHANGE #
- #############################
- OSS_UPGRADE_VERSION = '35c7d2a9-6e23-4645-b975-e8693a1cef10'
- OSS_PRODUCT_NAME = 'Grafana OSS'
- ENTERPRISE_UPGRADE_VERSION = 'd534ec50-476b-4edc-a25e-fe854c949f4f'
- ENTERPRISE_PRODUCT_NAME = 'Grafana Enterprise'
- #############################
- # CONSTANTS
- #############################
- MSI_GENERATOR_VERSION = '1.0.0'
- #############################
- # PATHS
- #############################
- WIX_HOME = '/home/xclient/wix'
- WINE_CMD = '/usr/bin/wine64' # or just wine for 32bit
- CANDLE = '{} {}/candle.exe'.format(WINE_CMD, WIX_HOME)
- LIGHT = '{} {}/light.exe'.format(WINE_CMD, WIX_HOME)
- HEAT = '{} {}/heat.exe'.format(WINE_CMD, WIX_HOME)
- NSSM_VERSION = '2.24'
- DIST_LOCATION = '/tmp/dist'
- #############################
- #
- #############################
- grafana_oss = {
- 'feature_component_group_refs': [
- 'GrafanaX64',
- 'GrafanaServiceX64',
- 'GrafanaFirewallExceptionsGroup'
- ],
- 'directory_refs': [
- 'GrafanaX64Dir'
- ],
- 'components': [
- 'grafana.wxs',
- 'grafana-service.wxs',
- 'grafana-firewall.wxs'
- ]
- }
- #
- # Grafana 6 includes new datasources with long paths
- #
- def remove_long_paths():
- print('Removing long pathed files - these are not needed to run grafana')
- long_files = [
- '/tmp/a/grafana/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_querystring_builder.test.ts',
- '/tmp/a/grafana/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_querystring_builder.ts',
- '/tmp/a/grafana/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/azure_log_analytics_datasource.test.ts',
- '/tmp/a/grafana/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/azure_log_analytics_datasource.ts',
- '/tmp/a/grafana/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_datasource.test.ts',
- '/tmp/a/grafana/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_datasource.ts',
- '/tmp/a/grafana/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_filter_builder.test.ts',
- '/tmp/a/grafana/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_filter_builder.ts',
- '/tmp/a/grafana/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AnalyticsConfig.test.tsx',
- '/tmp/a/grafana/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AzureCredentialsForm.test.tsx',
- '/tmp/a/grafana/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/InsightsConfig.test.tsx',
- '/tmp/a/grafana/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/__snapshots__/AnalyticsConfig.test.tsx.snap',
- '/tmp/a/grafana/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/__snapshots__/AzureCredentialsForm.test.tsx.snap',
- '/tmp/a/grafana/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/__snapshots__/InsightsConfig.test.tsx.snap'
- ]
- for file in long_files:
- if os.path.isfile(file):
- print('Removing: {}'.format(file))
- os.remove(file)
- else:
- print('Skipped: {}'.format(file))
- def build_oss(zip_file, extracted_name, PRODUCT_VERSION, config, features):
- # keep reference to source directory, will need to switch back and
- # forth during the process
- src_dir = os.getcwd()
- # target_dir = tempfile.TemporaryDirectory()
- if not os.path.isdir('/tmp/a'):
- os.mkdir('/tmp/a')
- target_dir_name = '/tmp/a'
- extract_zip(zip_file, target_dir_name)
- # the zip file contains a version, which will not work when upgrading,
- # and ends up with paths longer
- # than light.exe can parse (windows issue)
- # Once extracted, rename it to grafana without the version included
- zip_file_path = '{}/{}'.format(target_dir_name, extracted_name)
- rename_to = '{}/grafana'.format(target_dir_name)
- print('Renaming extracted path {} to {}'.format(zip_file_path, rename_to))
- os.system('ls -al /tmp/a')
- print('Before:')
- os.rename(zip_file_path, rename_to)
- print('After:')
- os.system('ls -al /tmp/a')
- # cleanup due to MSI API limitation
- remove_long_paths()
- #
- # HEAT
- #
- # Collects the files from the path given and generates wxs file
- #
- print('Heat Harvesting')
- cgname = 'GrafanaX64'
- cgdir = 'GrafanaX64Dir'
- if not os.path.isdir('/tmp/scratch'):
- os.mkdir('/tmp/scratch')
- os.chdir('/tmp/scratch')
- outfile = 'grafana-oss.wxs'
- # important flags
- # -srd - prevents the parent directory name from being included in the
- # harvest
- # -cg - component group to be referenced in main wxs file
- # -fr - directory ref to be used in main wxs file
- try:
- cmd = '''
- {} dir {} \
- -platform x64 \
- -sw5150 \
- -srd \
- -cg {} \
- -gg \
- -sfrag \
- -dr {} \
- -template fragment \
- -out {}'''.strip().format(HEAT, target_dir_name, cgname, cgdir, outfile)
- print(cmd)
- os.system(cmd)
- except Exception as ex:
- print(ex)
- shutil.copy2(outfile, target_dir_name)
- nssm_file = get_nssm('/tmp/cache', NSSM_VERSION)
- if not os.path.isdir(target_dir_name + '/nssm'):
- os.mkdir(target_dir_name + '/nssm')
- extract_zip(nssm_file, target_dir_name + '/nssm')
- print('HARVEST COMPLETE')
- os.chdir(src_dir)
- generate_firewall_wxs(env, PRODUCT_VERSION, '/tmp/scratch/grafana-firewall.wxs', target_dir_name)
- generate_service_wxs(env, PRODUCT_VERSION, '/tmp/scratch/grafana-service.wxs', target_dir_name, NSSM_VERSION)
- generate_product_wxs(env, config, features, '/tmp/scratch/product.wxs', target_dir_name)
- print('GENERATE COMPLETE')
- copy_static_files(target_dir_name)
- print('COPY STATIC COMPLETE')
- #
- # CANDLE needs to run in the scratch dir
- os.chdir('/tmp/scratch')
- try:
- filename = 'grafana-service.wxs'
- cmd = '{} -ext WixFirewallExtension -ext WixUtilExtension -v -arch x64 {}'.format(CANDLE, filename)
- print(cmd)
- os.system(cmd)
- shutil.copy2('grafana-service.wixobj', target_dir_name)
- #
- filename = 'grafana-firewall.wxs'
- cmd = '{} -ext WixFirewallExtension -ext WixUtilExtension -v -arch x64 {}'.format(
- CANDLE,
- filename)
- print(cmd)
- os.system(cmd)
- shutil.copy2('grafana-firewall.wixobj', target_dir_name)
- #
- filename = 'grafana-oss.wxs'
- cmd = '{} -ext WixFirewallExtension -ext WixUtilExtension -v -arch x64 {}'.format(
- CANDLE,
- filename)
- print(cmd)
- os.system(cmd)
- shutil.copy2('grafana-oss.wixobj', target_dir_name)
- #
- filename = 'product.wxs'
- cmd = '{} -ext WixFirewallExtension -ext WixUtilExtension -v -arch x64 {}'.format(
- CANDLE,
- filename)
- print(cmd)
- os.system(cmd)
- shutil.copy2('product.wixobj', target_dir_name)
- except Exception as ex:
- print(ex)
- print('CANDLE COMPLETE')
- ############################
- # LIGHT - Assemble the MSI
- ############################
- os.chdir(target_dir_name)
- os.system('cp -pr nssm/nssm-2.24 .')
- try:
- cmd = '''
- {} \
- -cultures:en-US \
- -ext WixUIExtension.dll -ext WixFirewallExtension -ext WixUtilExtension \
- -v -sval -spdb \
- grafana-service.wixobj \
- grafana-firewall.wixobj \
- grafana-oss.wixobj \
- product.wixobj \
- -out grafana.msi'''.strip().format(LIGHT)
- print(cmd)
- os.system(cmd)
- except Exception as ex:
- print(ex)
- # copy to scratch with version included
- msi_filename = '/tmp/scratch/{}.windows-amd64.msi'.format(extracted_name)
- shutil.copy2('grafana.msi', msi_filename)
- os.system('ls -al /tmp/scratch')
- print('LIGHT COMPLETE')
- # finally cleanup
- # extract_dir.cleanup()
- def main(file_loader, env, grafana_version, zip_file, extracted_name):
- UPGRADE_VERSION = OSS_UPGRADE_VERSION
- GRAFANA_VERSION = grafana_version
- PRODUCT_NAME = OSS_PRODUCT_NAME
- # PRODUCT_VERSION=GRAFANA_VERSION
- # MSI version cannot have anything other
- # than a x.x.x.x format, numbers only
- PRODUCT_VERSION = GRAFANA_VERSION.split('-')[0]
- config = {
- 'grafana_version': PRODUCT_VERSION,
- 'upgrade_code': UPGRADE_VERSION,
- 'product_name': PRODUCT_NAME,
- 'manufacturer': 'Grafana Labs'
- }
- features = [
- {
- 'name': 'GrafanaOSS',
- 'title': PRODUCT_NAME,
- 'component_groups': [
- {
- 'ref_id': 'GrafanaX64',
- 'directory': 'GrafanaX64Dir'
- }
- ]
- },
- {
- 'name': 'GrafanaService',
- 'title': 'Run Grafana as a Service',
- 'component_groups': [
- {
- 'ref_id': 'GrafanaServiceX64',
- 'directory': 'GrafanaServiceX64Dir'
- }
- ]
- }
- ]
- build_oss(zip_file, extracted_name, PRODUCT_VERSION, config, features)
- if __name__ == '__main__':
- print('MSI Generator Version: {}'.format(MSI_GENERATOR_VERSION))
- parser = argparse.ArgumentParser(
- description='Grafana MSI Generator',
- formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=90, width=110), add_help=True)
- parser.add_argument(
- '-p',
- '--premium',
- help='Include premium plugins',
- dest='premium', action='store_true')
- parser.add_argument(
- '-e',
- '--enterprise',
- help='Use Enterprise build',
- dest='enterprise',
- action='store_true')
- parser.set_defaults(enterprise=False, premium=False)
- parser.add_argument('-b', '--build', help='build to download')
- args = parser.parse_args()
- file_loader = FileSystemLoader('templates')
- env = Environment(loader=file_loader)
- grafana_version = None
- grafana_hash = None
- is_enterprise = False
- if not os.path.isdir(DIST_LOCATION):
- os.mkdir(DIST_LOCATION)
- # if a build version is specified, pull it
- if args.build:
- grafana_version = args.build
- print('Version Specified: {}'.format(grafana_version))
- else:
- grafana_version, grafana_hash, is_enterprise = detect_version(DIST_LOCATION)
- # check for enterprise flag
- if args.enterprise:
- grafana_version = 'enterprise-{}'.format(args.build)
- #
- print('Detected Version: {}'.format(grafana_version))
- if grafana_hash:
- print('Detected Hash: {}'.format(grafana_hash))
- print('Enterprise: {}'.format(is_enterprise))
- if is_enterprise:
- zip_file = '{}/grafana-enterprise-{}.windows-amd64.zip'.format(DIST_LOCATION, grafana_version)
- extracted_name = 'grafana-enterprise-{}'.format(grafana_version)
- else:
- # the file can have a build hash
- if grafana_hash:
- zip_file = '{}/grafana-{}-{}.windows-amd64.zip'.format(DIST_LOCATION, grafana_version, grafana_hash)
- extracted_name = 'grafana-{}-{}'.format(grafana_version, grafana_hash)
- else:
- zip_file = '{}/grafana-{}.windows-amd64.zip'.format(DIST_LOCATION, grafana_version)
- extracted_name = 'grafana-{}'.format(grafana_version)
- print('ZipFile: {}'.format(zip_file))
- # check if file downloaded
- if not os.path.isfile(zip_file):
- zip_file = get_zip(grafana_version, zip_file)
- main(file_loader, env, grafana_version, zip_file, extracted_name)
|