Pārlūkot izejas kodu

Add Windows MSI generation to build process (#16502)

- add MSI generation to build process
Brian Gann 6 gadi atpakaļ
vecāks
revīzija
31ea0122a0
24 mainītis faili ar 1181 papildinājumiem un 0 dzēšanām
  1. 37 0
      .circleci/config.yml
  2. 44 0
      scripts/build/ci-msi-build/README.md
  3. 28 0
      scripts/build/ci-msi-build/ci-msi-build-oss.sh
  4. 5 0
      scripts/build/ci-msi-build/oss/Makefile
  5. BIN
      scripts/build/ci-msi-build/oss/cache/nssm-2.24.zip
  6. 28 0
      scripts/build/ci-msi-build/oss/ci-wrapper.sh
  7. 13 0
      scripts/build/ci-msi-build/oss/docker-compose.yml
  8. 332 0
      scripts/build/ci-msi-build/oss/generator/build.py
  9. 123 0
      scripts/build/ci-msi-build/oss/generator/utils.py
  10. 13 0
      scripts/build/ci-msi-build/oss/light.exe.config
  11. 3 0
      scripts/build/ci-msi-build/oss/requirements.txt
  12. BIN
      scripts/build/ci-msi-build/oss/resources/images/grafana_dialog_background.bmp
  13. BIN
      scripts/build/ci-msi-build/oss/resources/images/grafana_dialog_background.png
  14. BIN
      scripts/build/ci-msi-build/oss/resources/images/grafana_icon.ico
  15. BIN
      scripts/build/ci-msi-build/oss/resources/images/grafana_top_banner.bmp
  16. BIN
      scripts/build/ci-msi-build/oss/resources/images/grafana_top_banner.png
  17. BIN
      scripts/build/ci-msi-build/oss/resources/images/grafana_top_banner_white.bmp
  18. 202 0
      scripts/build/ci-msi-build/oss/resources/license/LICENSE.md
  19. 206 0
      scripts/build/ci-msi-build/oss/resources/license/LICENSE.rtf
  20. 19 0
      scripts/build/ci-msi-build/oss/templates/common/grafana-firewall.wxs.j2
  21. 59 0
      scripts/build/ci-msi-build/oss/templates/common/grafana-service.wxs.j2
  22. 54 0
      scripts/build/ci-msi-build/oss/templates/common/product.wxs.j2
  23. 12 0
      scripts/build/ci-msi-build/oss/templates/oracle/oracle-environment.wxs.j2
  24. 3 0
      scripts/build/ci-msi-build/oss/wrapper.sh

+ 37 - 0
.circleci/config.yml

@@ -552,6 +552,21 @@ jobs:
           name: Update RPM repository
           command: './scripts/build/update_repo/update-rpm.sh "oss" "$GPG_KEY_PASSWORD" "$CIRCLE_TAG" "dist"'
 
+  build-oss-msi:
+    docker:
+      - image: grafana/wix-toolset-ci:v3
+    steps:
+      - checkout
+      - attach_workspace:
+          at: .
+      - run:
+          name: Build OSS MSI
+          command: './scripts/build/ci-msi-build/ci-msi-build-oss.sh'
+      - persist_to_workspace:
+          root: .
+          paths:
+            - dist/grafana-*.msi
+
   store-build-artifacts:
     docker:
       - image: circleci/node:8
@@ -590,6 +605,7 @@ workflows:
             - backend-lint
             - mysql-integration-test
             - postgres-integration-test
+            - build-oss-msi
           filters: *filter-only-master
       - grafana-docker-master:
           requires:
@@ -613,6 +629,16 @@ workflows:
             - postgres-integration-test
             - build-all-enterprise
           filters: *filter-only-master
+      - build-oss-msi:
+          requires:
+            - build-all
+            - test-backend
+            - test-frontend
+            - codespell
+            - backend-lint
+            - mysql-integration-test
+            - postgres-integration-test
+          filters: *filter-only-master
 
   release:
     jobs:
@@ -641,6 +667,7 @@ workflows:
             - backend-lint
             - mysql-integration-test
             - postgres-integration-test
+            - build-oss-msi
           filters: *filter-only-release
       - deploy-enterprise-release:
           requires:
@@ -664,6 +691,16 @@ workflows:
             - mysql-integration-test
             - postgres-integration-test
           filters: *filter-only-release
+      - build-oss-msi:
+          requires:
+            - build-all
+            - test-backend
+            - test-frontend
+            - codespell
+            - backend-lint
+            - mysql-integration-test
+            - postgres-integration-test
+          filters: *filter-only-master
 
   build-branches-and-prs:
       jobs:

+ 44 - 0
scripts/build/ci-msi-build/README.md

@@ -0,0 +1,44 @@
+# Grafana MSI Generator
+
+Creates a docker image that can be included within CircleCI or run locally to generate an MSI for Grafana.
+
+## Docker Image
+
+The docker image is created and published via CircleCI, and can also be built locally.
+
+The image is self contained with all of the code in `/master`.
+The detection process expects a zip file in `/master/dist`.
+
+There are two patterns that will be matched for a build in the dist directory:
+```
+grafana-6.0.0-ca0bc2c5pre3.windows-amd64.zip
+grafana-5.4.3.windows-amd64.zip
+```
+
+### Building an MSI
+
+The process is automated to expect a dist directory, and will build an msi for first matching grafana-*.windows-amd64.zip file found.
+
+```
+grafana-5.4.3.windows-amd64.zip
+```
+
+## CircleCI
+
+
+
+## Manual
+
+A wrapper script takes a single argument for the path to a zip file, or searches for a file in dist.
+
+A manual build can be initiated using docker-compose
+```
+cd oss
+docker-compose up --build
+```
+## Automated
+
+## Testing
+
+## Change Log
+v1.0.0 - initial commit

+ 28 - 0
scripts/build/ci-msi-build/ci-msi-build-oss.sh

@@ -0,0 +1,28 @@
+#!/bin/bash
+set -e
+WORKING_DIRECTORY=`pwd`
+# copy zip file to /tmp/dist
+mkdir -p /tmp/dist
+cp ./dist/*.zip /tmp/dist
+echo "Contents of /tmp/dist"
+ls -al /tmp/dist
+
+# nssm download has been unreliable, use a cached copy of it
+echo "Caching NSSM"
+mkdir -p /tmp/cache
+cp ./scripts/build/ci-msi-build/oss/cache/nssm-2.24.zip /tmp/cache
+# a build can be specified, which will be pulled down
+#python3 generator/build.py --build 5.4.3
+#echo "LIGHT config"
+#ls -al /home/xclient/wix/light.exe.config
+#cat /home/xclient/wix/light.exe.config
+#cp ./scripts/build/ci-msi-build/oss/light.exe.config /home/xclient/wix/light.exe.config
+#cat /home/xclient/wix/light.exe.config
+cd ./scripts/build/ci-msi-build/oss
+echo "Building MSI"
+python3 generator/build.py "$@"
+chmod a+x /tmp/scratch/*.msi
+echo "MSI: Copy to $WORKING_DIRECTORY/dist"
+cp /tmp/scratch/*.msi $WORKING_DIRECTORY/dist
+echo "MSI: contents of $WORKING_DIRECTORY/dist"
+ls -al $WORKING_DIRECTORY/dist

+ 5 - 0
scripts/build/ci-msi-build/oss/Makefile

@@ -0,0 +1,5 @@
+all: build
+
+build:
+	pip3 install -r requirements.txt
+	python3 generator/build.py

BIN
scripts/build/ci-msi-build/oss/cache/nssm-2.24.zip


+ 28 - 0
scripts/build/ci-msi-build/oss/ci-wrapper.sh

@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Build will be found in ./dist and ./dist-enterprise
+# integrated circleci will have all of the code in /master
+# and the builds will be found in $HOME
+mkdir -p /tmp/dist
+if [ -d '/home/xclient/repo/dist/' ]; then
+  ls -al /home/xclient/repo/dist/
+  cp /home/xclient/repo/dist/*.zip /tmp/dist/
+  echo "Contents of /tmp/dist"
+  ls -al /tmp/dist
+fi
+# nssm download has been unreliable, use a cached copy of it
+echo "Caching NSSM"
+mkdir -p /tmp/cache
+cp /master/cache/nssm-2.24.zip /tmp/cache
+# a build can be specified, which will be pulled down
+#python3 generator/build.py --build 5.4.3
+echo "LIGHT config"
+ls -al /home/xclient/wix/light.exe.config
+cat /home/xclient/wix/light.exe.config
+cp /master/light.exe.config /home/xclient/wix/light.exe.config
+cat /home/xclient/wix/light.exe.config
+cd /master
+echo "Building MSI"
+python3 generator/build.py "$@"
+#
+#

+ 13 - 0
scripts/build/ci-msi-build/oss/docker-compose.yml

@@ -0,0 +1,13 @@
+version: '3'
+services:
+  wix:
+    build: './docker'
+    command: /oss/wrapper.sh
+    # important: wine is setup for the user xclient
+    user: xclient
+    volumes:
+      - ../oss:/oss
+      - ../master/templates:/oss/templates
+      - ../master/resources:/oss/resources
+    environment:
+      - TERM=linux

+ 332 - 0
scripts/build/ci-msi-build/oss/generator/build.py

@@ -0,0 +1,332 @@
+#!/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'
+    ]
+    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)

+ 123 - 0
scripts/build/ci-msi-build/oss/generator/utils.py

@@ -0,0 +1,123 @@
+import zipfile
+import os
+import glob
+import re
+import shutil
+import wget
+from jinja2 import Template, Environment, FileSystemLoader
+
+
+
+def extract_zip(filename, target_dir):
+    with zipfile.ZipFile(filename, 'r') as zip_ref:
+        zip_ref.extractall(target_dir)
+
+
+def get_nssm(tmpPath, version):
+    if not os.path.isdir(tmpPath):
+        os.mkdir(tmpPath)
+    target_filename = '{}/nssm-{}.zip'.format(tmpPath, version)
+    exists = os.path.isfile(target_filename)
+    if exists:
+        return target_filename
+    url = 'https://nssm.cc/release/nssm-{}.zip'.format(version)
+    print('NSSM url is {}'.format(url))
+    filename = wget.download(url, out=target_filename, bar=wget.bar_thermometer)
+    return filename
+
+
+def get_zip(version, target_filename):
+    exists = os.path.isfile(target_filename)
+    if exists:
+        return target_filename
+    url = 'https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-{}.windows-amd64.zip'.format(version)
+    #url = 'https://dl.grafana.com/enterprise/release/grafana-enterprise-{}.windows-amd64.zip'.format(version)
+    filename = wget.download(url, out=target_filename, bar=wget.bar_thermometer)
+    return filename
+
+
+#
+#
+#
+def detect_version(dist_path):
+    detectedVersion = ''
+    detectedHash = ''
+    isEnterprise = False
+    print("Detecting Version...")
+    # grafana-6.0.0-ca0bc2c5pre3.windows-amd64.zip
+    # get files in directory matching pattern
+    fileList = glob.glob(dist_path + '/grafana*.windows-amd64.zip')
+    print(fileList)
+    if len(fileList) == 0:
+        print('Skipping detection, no matches')
+        return
+    firstFile = fileList[0]
+    p1 = re.search(r'grafana-(\d\.\d\.\d)\.windows-amd64.zip$', firstFile)
+    p2 = re.search(r'grafana-(\d\.\d\.\d)-(.*)\.windows-amd64.zip$', firstFile)
+    if p1:
+        detectedVersion = p1.group(1)
+    if p2:
+        detectedVersion = p2.group(1)
+        detectedHash = p2.group(2)
+    return detectedVersion, detectedHash, isEnterprise
+
+    #if os.path.isdir(dist_path + 'enterprise-dist'):
+    #    # grafana-enterprise-6.0.0-29b28127pre3.windows-amd64.zip
+    #    # get files in directory matching pattern
+    #    fileList = glob.glob(dist_path + '/enterprise-dist/grafana*.windows-amd64.zip')
+    #    firstFile = fileList[0]
+    #    p1 = re.search(r'grafana-enterprise-(\d\.\d\.\d)\.windows-amd64.zip$', firstFile)
+    #    p2 = re.search(r'grafana-enterprise-(\d\.\d\.\d)-(.*)\.windows-amd64.zip$', firstFile)
+    #    if p1:
+    #        detectedVersion = p1.group(1)
+    #        isEnterprise = True
+    #    if p2:
+    #        detectedVersion = p2.group(1)
+    #        detectedHash = p2.group(2)
+    #        isEnterprise = True
+    #    return detectedVersion, detectedHash, isEnterprise
+
+
+def generate_product_wxs(env, config, features, scratch_file, target_dir):
+    template = env.get_template('common/product.wxs.j2')
+    output = template.render(config=config, features=features)
+    fh = open(scratch_file, 'w')
+    fh.write(output)
+    fh.close()
+    shutil.copy2(scratch_file, target_dir)
+
+def generate_service_wxs(env, grafana_version, scratch_file, target_dir, nssm_version='2.24'):
+    template = env.get_template('common/grafana-service.wxs.j2')
+    output = template.render(grafana_version=grafana_version, nssm_version=nssm_version)
+    fh = open(scratch_file, 'w')
+    fh.write(output)
+    fh.close()
+    shutil.copy2(scratch_file, target_dir)
+
+def generate_firewall_wxs(env, grafana_version, scratch_file, target_dir):
+    os.system("ls -al templates")
+    template = env.get_template('common/grafana-firewall.wxs.j2')
+    output = template.render(grafana_version=grafana_version)
+    fh = open(scratch_file, 'w')
+    fh.write(output)
+    fh.close()
+    shutil.copy2(scratch_file, target_dir)
+
+
+def generate_oracle_environment_wxs(env, instant_client_version, scratch_file, target_dir):
+    template = env.get_template('oracle/oracle-environment.wxs.j2')
+    output = template.render(instant_client_version=instant_client_version)
+    fh = open(scratch_file, 'w')
+    fh.write(output)
+    fh.close()
+    shutil.copy2(scratch_file, target_dir)
+
+def copy_static_files(target_dir):
+    for item in os.listdir('resources/images'):
+        s = os.path.join('resources/images', item)
+        d = os.path.join(target_dir, item)
+        shutil.copy2(s, d)
+    for item in os.listdir('resources/license'):
+        s = os.path.join('resources/license', item)
+        d = os.path.join(target_dir, item)
+        shutil.copy2(s, d)

+ 13 - 0
scripts/build/ci-msi-build/oss/light.exe.config

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
+
+<configuration>
+    <startup useLegacyV2RuntimeActivationPolicy="true">
+        <supportedRuntime version="v4.0" />
+        <supportedRuntime version="v2.0.50727" />
+    </startup>
+    <runtime>
+        <loadFromRemoteSources enabled="true"/>
+		 <AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" />
+    </runtime>
+</configuration>

+ 3 - 0
scripts/build/ci-msi-build/oss/requirements.txt

@@ -0,0 +1,3 @@
+Jinja2>=2.10
+MarkupSafe>=1.1.0
+wget>=3.2

BIN
scripts/build/ci-msi-build/oss/resources/images/grafana_dialog_background.bmp


BIN
scripts/build/ci-msi-build/oss/resources/images/grafana_dialog_background.png


BIN
scripts/build/ci-msi-build/oss/resources/images/grafana_icon.ico


BIN
scripts/build/ci-msi-build/oss/resources/images/grafana_top_banner.bmp


BIN
scripts/build/ci-msi-build/oss/resources/images/grafana_top_banner.png


BIN
scripts/build/ci-msi-build/oss/resources/images/grafana_top_banner_white.bmp


+ 202 - 0
scripts/build/ci-msi-build/oss/resources/license/LICENSE.md

@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.

+ 206 - 0
scripts/build/ci-msi-build/oss/resources/license/LICENSE.rtf

@@ -0,0 +1,206 @@
+{\rtf1\ansi\deff0\nouicompat{\fonttbl{\f0\fnil\fcharset0 Courier New;}}
+{\*\generator Riched20 6.3.9600}\viewkind4\uc1 
+\pard\f0\fs22\lang1033\par
+                                 Apache License\par
+                           Version 2.0, January 2004\par
+                        http://www.apache.org/licenses/\par
+\par
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\par
+\par
+   1. Definitions.\par
+\par
+      "License" shall mean the terms and conditions for use, reproduction,\par
+      and distribution as defined by Sections 1 through 9 of this document.\par
+\par
+      "Licensor" shall mean the copyright owner or entity authorized by\par
+      the copyright owner that is granting the License.\par
+\par
+      "Legal Entity" shall mean the union of the acting entity and all\par
+      other entities that control, are controlled by, or are under common\par
+      control with that entity. For the purposes of this definition,\par
+      "control" means (i) the power, direct or indirect, to cause the\par
+      direction or management of such entity, whether by contract or\par
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the\par
+      outstanding shares, or (iii) beneficial ownership of such entity.\par
+\par
+      "You" (or "Your") shall mean an individual or Legal Entity\par
+      exercising permissions granted by this License.\par
+\par
+      "Source" form shall mean the preferred form for making modifications,\par
+      including but not limited to software source code, documentation\par
+      source, and configuration files.\par
+\par
+      "Object" form shall mean any form resulting from mechanical\par
+      transformation or translation of a Source form, including but\par
+      not limited to compiled object code, generated documentation,\par
+      and conversions to other media types.\par
+\par
+      "Work" shall mean the work of authorship, whether in Source or\par
+      Object form, made available under the License, as indicated by a\par
+      copyright notice that is included in or attached to the work\par
+      (an example is provided in the Appendix below).\par
+\par
+      "Derivative Works" shall mean any work, whether in Source or Object\par
+      form, that is based on (or derived from) the Work and for which the\par
+      editorial revisions, annotations, elaborations, or other modifications\par
+      represent, as a whole, an original work of authorship. For the purposes\par
+      of this License, Derivative Works shall not include works that remain\par
+      separable from, or merely link (or bind by name) to the interfaces of,\par
+      the Work and Derivative Works thereof.\par
+\par
+      "Contribution" shall mean any work of authorship, including\par
+      the original version of the Work and any modifications or additions\par
+      to that Work or Derivative Works thereof, that is intentionally\par
+      submitted to Licensor for inclusion in the Work by the copyright owner\par
+      or by an individual or Legal Entity authorized to submit on behalf of\par
+      the copyright owner. For the purposes of this definition, "submitted"\par
+      means any form of electronic, verbal, or written communication sent\par
+      to the Licensor or its representatives, including but not limited to\par
+      communication on electronic mailing lists, source code control systems,\par
+      and issue tracking systems that are managed by, or on behalf of, the\par
+      Licensor for the purpose of discussing and improving the Work, but\par
+      excluding communication that is conspicuously marked or otherwise\par
+      designated in writing by the copyright owner as "Not a Contribution."\par
+\par
+      "Contributor" shall mean Licensor and any individual or Legal Entity\par
+      on behalf of whom a Contribution has been received by Licensor and\par
+      subsequently incorporated within the Work.\par
+\par
+   2. Grant of Copyright License. Subject to the terms and conditions of\par
+      this License, each Contributor hereby grants to You a perpetual,\par
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\par
+      copyright license to reproduce, prepare Derivative Works of,\par
+      publicly display, publicly perform, sublicense, and distribute the\par
+      Work and such Derivative Works in Source or Object form.\par
+\par
+   3. Grant of Patent License. Subject to the terms and conditions of\par
+      this License, each Contributor hereby grants to You a perpetual,\par
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\par
+      (except as stated in this section) patent license to make, have made,\par
+      use, offer to sell, sell, import, and otherwise transfer the Work,\par
+      where such license applies only to those patent claims licensable\par
+      by such Contributor that are necessarily infringed by their\par
+      Contribution(s) alone or by combination of their Contribution(s)\par
+      with the Work to which such Contribution(s) was submitted. If You\par
+      institute patent litigation against any entity (including a\par
+      cross-claim or counterclaim in a lawsuit) alleging that the Work\par
+      or a Contribution incorporated within the Work constitutes direct\par
+      or contributory patent infringement, then any patent licenses\par
+      granted to You under this License for that Work shall terminate\par
+      as of the date such litigation is filed.\par
+\par
+   4. Redistribution. You may reproduce and distribute copies of the\par
+      Work or Derivative Works thereof in any medium, with or without\par
+      modifications, and in Source or Object form, provided that You\par
+      meet the following conditions:\par
+\par
+      (a) You must give any other recipients of the Work or\par
+          Derivative Works a copy of this License; and\par
+\par
+      (b) You must cause any modified files to carry prominent notices\par
+          stating that You changed the files; and\par
+\par
+      (c) You must retain, in the Source form of any Derivative Works\par
+          that You distribute, all copyright, patent, trademark, and\par
+          attribution notices from the Source form of the Work,\par
+          excluding those notices that do not pertain to any part of\par
+          the Derivative Works; and\par
+\par
+      (d) If the Work includes a "NOTICE" text file as part of its\par
+          distribution, then any Derivative Works that You distribute must\par
+          include a readable copy of the attribution notices contained\par
+          within such NOTICE file, excluding those notices that do not\par
+          pertain to any part of the Derivative Works, in at least one\par
+          of the following places: within a NOTICE text file distributed\par
+          as part of the Derivative Works; within the Source form or\par
+          documentation, if provided along with the Derivative Works; or,\par
+          within a display generated by the Derivative Works, if and\par
+          wherever such third-party notices normally appear. The contents\par
+          of the NOTICE file are for informational purposes only and\par
+          do not modify the License. You may add Your own attribution\par
+          notices within Derivative Works that You distribute, alongside\par
+          or as an addendum to the NOTICE text from the Work, provided\par
+          that such additional attribution notices cannot be construed\par
+          as modifying the License.\par
+\par
+      You may add Your own copyright statement to Your modifications and\par
+      may provide additional or different license terms and conditions\par
+      for use, reproduction, or distribution of Your modifications, or\par
+      for any such Derivative Works as a whole, provided Your use,\par
+      reproduction, and distribution of the Work otherwise complies with\par
+      the conditions stated in this License.\par
+\par
+   5. Submission of Contributions. Unless You explicitly state otherwise,\par
+      any Contribution intentionally submitted for inclusion in the Work\par
+      by You to the Licensor shall be under the terms and conditions of\par
+      this License, without any additional terms or conditions.\par
+      Notwithstanding the above, nothing herein shall supersede or modify\par
+      the terms of any separate license agreement you may have executed\par
+      with Licensor regarding such Contributions.\par
+\par
+   6. Trademarks. This License does not grant permission to use the trade\par
+      names, trademarks, service marks, or product names of the Licensor,\par
+      except as required for reasonable and customary use in describing the\par
+      origin of the Work and reproducing the content of the NOTICE file.\par
+\par
+   7. Disclaimer of Warranty. Unless required by applicable law or\par
+      agreed to in writing, Licensor provides the Work (and each\par
+      Contributor provides its Contributions) on an "AS IS" BASIS,\par
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\par
+      implied, including, without limitation, any warranties or conditions\par
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\par
+      PARTICULAR PURPOSE. You are solely responsible for determining the\par
+      appropriateness of using or redistributing the Work and assume any\par
+      risks associated with Your exercise of permissions under this License.\par
+\par
+   8. Limitation of Liability. In no event and under no legal theory,\par
+      whether in tort (including negligence), contract, or otherwise,\par
+      unless required by applicable law (such as deliberate and grossly\par
+      negligent acts) or agreed to in writing, shall any Contributor be\par
+      liable to You for damages, including any direct, indirect, special,\par
+      incidental, or consequential damages of any character arising as a\par
+      result of this License or out of the use or inability to use the\par
+      Work (including but not limited to damages for loss of goodwill,\par
+      work stoppage, computer failure or malfunction, or any and all\par
+      other commercial damages or losses), even if such Contributor\par
+      has been advised of the possibility of such damages.\par
+\par
+   9. Accepting Warranty or Additional Liability. While redistributing\par
+      the Work or Derivative Works thereof, You may choose to offer,\par
+      and charge a fee for, acceptance of support, warranty, indemnity,\par
+      or other liability obligations and/or rights consistent with this\par
+      License. However, in accepting such obligations, You may act only\par
+      on Your own behalf and on Your sole responsibility, not on behalf\par
+      of any other Contributor, and only if You agree to indemnify,\par
+      defend, and hold each Contributor harmless for any liability\par
+      incurred by, or claims asserted against, such Contributor by reason\par
+      of your accepting any such warranty or additional liability.\par
+\par
+   END OF TERMS AND CONDITIONS\par
+\par
+   APPENDIX: How to apply the Apache License to your work.\par
+\par
+      To apply the Apache License to your work, attach the following\par
+      boilerplate notice, with the fields enclosed by brackets "[]"\par
+      replaced with your own identifying information. (Don't include\par
+      the brackets!)  The text should be enclosed in the appropriate\par
+      comment syntax for the file format. We also recommend that a\par
+      file or class name and description of purpose be included on the\par
+      same "printed page" as the copyright notice for easier\par
+      identification within third-party archives.\par
+\par
+   Copyright [yyyy] [name of copyright owner]\par
+\par
+   Licensed under the Apache License, Version 2.0 (the "License");\par
+   you may not use this file except in compliance with the License.\par
+   You may obtain a copy of the License at\par
+\par
+       http://www.apache.org/licenses/LICENSE-2.0\par
+\par
+   Unless required by applicable law or agreed to in writing, software\par
+   distributed under the License is distributed on an "AS IS" BASIS,\par
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\par
+   See the License for the specific language governing permissions and\par
+   limitations under the License.\par
+}
+

+ 19 - 0
scripts/build/ci-msi-build/oss/templates/common/grafana-firewall.wxs.j2

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
+     xmlns:fire="http://schemas.microsoft.com/wix/FirewallExtension">
+  <Fragment>
+      <ComponentGroup Id="GrafanaFirewallExceptionsGroup">
+        <Component Id="FirewallGrafanaServer" Guid="7278f07d-de6f-497f-9267-d5feb5216a5c" Directory="INSTALLDIR">
+          <File KeyPath="yes" Source="SourceDir\grafana\bin\grafana-server.exe">
+             <fire:FirewallException
+              Id="FWX1"
+              Name="Grafana Server TCP 3000"
+              Port="3000"
+              Profile="all"
+              Protocol="tcp"
+              Scope="any"/>
+          </File>
+        </Component>
+      </ComponentGroup>
+  </Fragment>
+</Wix>

+ 59 - 0
scripts/build/ci-msi-build/oss/templates/common/grafana-service.wxs.j2

@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
+     xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
+
+  <Fragment>
+    <ComponentGroup Id="GrafanaServiceX64">
+      <Component Id="nssm_component" Guid="*" Directory="INSTALLDIR">
+        <File Id="nssm" KeyPath="yes" Source="SourceDir\nssm-{{ nssm_version }}\win64\nssm.exe" />
+
+        <ServiceInstall Id="ServiceInstall"
+          Account="LocalSystem"
+          ErrorControl="normal"
+          Name="Grafana"
+          Start="auto"
+          Type="ownProcess"
+          Vital="yes"
+          Description="Grafana by Grafana Labs"
+          DisplayName="Grafana">
+          <ServiceConfig OnInstall="yes" OnReinstall="yes" DelayedAutoStart="no" />
+        </ServiceInstall>
+
+        <ServiceControl Id="ControlService"
+          Name="Grafana"
+          Wait="yes"
+          Start="install"
+          Stop="both"
+          Remove="uninstall"
+        />
+
+        <RegistryKey Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\Grafana">
+          <RegistryKey Key="Parameters">
+            <RegistryValue Name="AppDirectory" Value="[INSTALLDIR]grafana" Type="expandable" />
+            <RegistryValue Name="Application" Value="[INSTALLDIR]grafana\bin\grafana-server.exe" Type="expandable" />
+            <RegistryValue Name="AppParameters" Value='' Type="expandable" />
+
+            <RegistryValue Name="AppEnvironmentExtra" Type="multiString">
+              <MultiStringValue>LOG_LEVEL=DEBUG</MultiStringValue>
+            </RegistryValue>
+         
+            <RegistryValue Name="AppStdout" Value="[LOGDIR]grafana-service.log" Type="expandable" />
+            <RegistryValue Name="AppStderr" Value="[LOGDIR]grafana-service.log" Type="expandable" />
+            <RegistryValue Name="AppRotateFiles" Value="1" Type="integer" />
+            <RegistryValue Name="AppRotateOnline" Value="1" Type="integer" />
+
+            <!-- Rotate after 100 MB -->
+            <RegistryValue Name="AppRotateBytes" Value="104857600" Type="integer" />
+            <RegistryValue Name="AppStdoutCopyAndTruncate" Value="1" Type="integer" />
+            <RegistryValue Name="AppStderrCopyAndTruncate" Value="1" Type="integer" />
+            <RegistryValue Name="AppRotateDelay" Value="1000" Type="integer" />
+
+            <RegistryKey Key="AppExit">
+              <RegistryValue Type="string" Value="Restart" />
+            </RegistryKey>
+          </RegistryKey>
+        </RegistryKey>
+      </Component>
+    </ComponentGroup>
+  </Fragment>
+</Wix>

+ 54 - 0
scripts/build/ci-msi-build/oss/templates/common/product.wxs.j2

@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+  <Product Id="*"
+    UpgradeCode="{{ config.upgrade_code }}"
+    Name="{{ config.product_name }}"
+    Version="{{ config.grafana_version }}"
+    Manufacturer="{{ config.manufacturer }}"
+    Language="1033">
+
+    <Package
+      Platform="x64"
+      InstallerVersion="200"
+      Compressed="yes"
+      Comments="Windows Installer Package"/>
+
+    <Media Id="1" Cabinet="product.cab" EmbedCab="yes"/>
+
+    <Icon Id="icon.ico" SourceFile="grafana_icon.ico"/>
+
+    <WixVariable Id="WixUILicenseRtf" Value="LICENSE.rtf" />
+    <WixVariable Id="WixUIBannerBmp" Value="grafana_top_banner_white.bmp" />
+    <WixVariable Id="WixUIDialogBmp" Value="grafana_dialog_background.bmp" />
+
+    <Property Id="ARPPRODUCTICON" Value="icon.ico" />
+    <Property Id="ARPHELPLINK" Value="https://www.grafana.com" />
+    <Property Id="ARPURLINFOABOUT" Value="https://www.grafana.com" />
+
+    <Directory Id="TARGETDIR" Name="SourceDir">
+      <Directory Id="ProgramFiles64Folder">
+        <Directory Id="INSTALLDIR" Name="GrafanaLabs">
+          {% for feature in features %}
+            {% for component_group in feature.component_groups %}
+              <Directory Id="{{component_group.directory}}"/>
+            {% endfor %}
+          {% endfor %}
+        </Directory>
+      </Directory>
+    </Directory>
+
+    <Feature Id="DefaultFeature" Title="Grafana" Display="expand" ConfigurableDirectory="INSTALLDIR">
+      {% for feature in features %}
+        <Feature Id="{{ feature.name }}Feature" Title="{{ feature.title }}" Level="1">
+          {% for component_group in feature.component_groups %}
+            <ComponentGroupRef Id="{{ component_group.ref_id }}"/>
+          {% endfor %}
+        </Feature>
+      {% endfor %}
+    </Feature>
+
+    <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
+		<UIRef Id="WixUI_FeatureTree"/>
+
+   </Product>
+</Wix>

+ 12 - 0
scripts/build/ci-msi-build/oss/templates/oracle/oracle-environment.wxs.j2

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
+     xmlns:fire="http://schemas.microsoft.com/wix/FirewallExtension">
+  <Fragment>
+      <ComponentGroup Id="OracleEnvironment">
+        <Component Id="ORACLE_ENV" Guid="13ed28fd-a2d8-45e3-9c0f-8ec8d9e3ad16" Directory="INSTALLDIR">
+          <Environment Id="OCI_LIB64" Name="OCI_LIB64" Value="[INSTALLDIR]instantclient_{{ instant_client_version }}" Permanent="yes" Part="last" Action="set" System="yes" />
+          <Environment Id="PATH" Name="PATH" Value="[INSTALLDIR]instantclient_{{instant_client_version}}" Permanent="yes" Part="last" Action="set" System="yes" />
+        </Component>
+      </ComponentGroup>
+  </Fragment>
+</Wix>

+ 3 - 0
scripts/build/ci-msi-build/oss/wrapper.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+cd /oss
+make