This commit is contained in:
Justin Donnelly
2022-01-31 11:59:58 -05:00
parent 3eceec14f5
commit 809ff9b013
66 changed files with 3603 additions and 0 deletions

8
sense-conductor/.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
*.terraform*
esoteric-parsec*json
*.tfstate*
*terraform-provider*
*.deb
*license.json
*history*
*functions.ps1

View File

@@ -0,0 +1,7 @@
# sense-conductor
Repository for QSEoW Orchestration
- Initial Goal is to collate disparate efforts.
- Componentize orchestration functions.
- Build framework for sustainable customer solution for orchestration of QSEoW Clusters

View File

View File

@@ -0,0 +1,24 @@
<?xml version="1.0"?>
<SharedPersistenceConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DbUserName>qliksenserepository</DbUserName>
<DbUserPassword>Qlik1234!</DbUserPassword>
<DbHost>10.54.242.47</DbHost>
<DbPort>5432</DbPort>
<RootDir>\\10.219.178.210\qlikshare</RootDir>
<StaticContentRootDir>\\10.219.178.210\qlikshare\StaticContent</StaticContentRootDir>
<ArchivedLogsDir>\\10.219.178.210\qlikshare\ArchivedLogs</ArchivedLogsDir>
<AppsDir>\\10.219.178.210\qlikshare\Apps</AppsDir>
<CreateCluster>true</CreateCluster>
<InstallLocalDb>false</InstallLocalDb>
<ConfigureDbListener>false</ConfigureDbListener>
<ListenAddresses>*</ListenAddresses>
<IpRange>0.0.0.0/0,::/0</IpRange>
<MaxConnections>100</MaxConnections>
<!-- <JoinCluster>true</JoinCluster> -->
<ConfigureLogging>true</ConfigureLogging>
<SetupLocalLoggingDb>false</SetupLocalLoggingDb>
<QLogsWriterPassword>Qlik1234!</QLogsWriterPassword>
<QLogsReaderPassword>Qlik1234!</QLogsReaderPassword>
<QLogsHostname>10.54.242.47</QLogsHostname>
<QLogsPort>5432</QLogsPort>
</SharedPersistenceConfiguration>

View File

@@ -0,0 +1,84 @@
terraform {
required_version = ">= 0.12"
}
provider "google-beta" {
credentials = file("esoteric-parsec-243510-a8f93bb5a906.json")
project = var.project_id
region = var.region
zone = var.zone
}
# Create random ID for VM suffix
resource "random_id" "vm_suffix" {
byte_length = 2
}
resource "google_compute_disk" "dataCen" {
provider = google-beta
name = "central-datadisk-${random_id.vm_suffix.hex}"
type = var.disk_type
zone = var.zone
# labels = {
# environment = "dev"
# }
size = 50
}
resource "google_compute_instance" "central" {
provider = google-beta
name = "central-${random_id.vm_suffix.hex}"
machine_type = var.vm_type
# min_cpu_platform commented out during testing - e2 instances do not support
# min_cpu_platform = var.min_cpu
zone = var.zone
# hostname = "central-${random_id.vm_suffix.hex}"
# tags = ["foo", "bar"]
# timeouts {
# create = "60m"
# delete = "2h"
# }
boot_disk {
initialize_params {
image = var.image
}
}
attached_disk {
source = google_compute_disk.dataCen.name
}
# lifecycle {
# ignore_changes = [attached_disk]
# }
network_interface {
network = "tactical-qlik-vpc"
subnetwork = "compute"
# access_config {
# network_tier = "STANDARD"
# }
}
metadata = {
windows-startup-script-url = "gs://qliksense/scripts/bootstrap.ps1"
}
service_account {
email = "terraform@esoteric-parsec-243510.iam.gserviceaccount.com"
scopes = ["cloud-platform"]
}
}
# psql -h <Private_IP> -Upostgres
# gcloud sql instances patch qseow-psql-<HEXID> --authorized-networks 172.16.12.0/28,172.16.1.0/24,172.16.10.0/24,172.16.2.0/24,172.16.11.0/24,192.88.99.0/24,11.0.0.0/24
# gcloud compute networks peerings update cloudsql-postgres-googleapis-com --network=NETWORK --export-subnet-routes-with-public-ip --project=PROJECT

View File

@@ -0,0 +1,21 @@
# Configure return values from google_sql_database_instance
# output "psql_ip_address" {
# value = google_sql_database_instance.qseow-psql.private_ip_address
# }
output "cen_name" {
value = google_compute_instance.central.name
}
# output "cen_ext_ip" {
# value = google_compute_instance.central.network_interface[0].access_config[0].nat_ip
# }
output "cen_int_ip" {
value = google_compute_instance.central.network_interface[0].network_ip
}
# output "serial_out" {
# value = data.google_compute_instance_serial_port.serial.contents
# }

View File

@@ -0,0 +1,17 @@
{
"project_id": "esoteric-parsec-243510",
"region": "europe-west1",
"zone": "europe-west1-d",
"private_network": "projects/esoteric-parsec-243510/global/networks/default",
"database_version": "POSTGRES_9_6",
"db_tier": "db-g1-small",
"file_tier": "BASIC_HDD",
"vm_type": "e2-highmem-4",
"min_cpu": "Intel Skylake",
"image": "gce-uefi-images/windows-2019",
"disk_type": "pd-ssd",
"availability_type": "REGIONAL",
"db_user": "postgres",
"user_name": "qlikadmin",
"user_password": "Qlik1234!"
}

View File

@@ -0,0 +1,134 @@
variable "project_id" {
type = string
description = "The project ID to manage the Cloud SQL resources"
}
variable "database_version" {
description = "The database version to use"
type = string
}
variable "region" {
type = string
description = "GCP Region"
default = "us-central1"
}
variable "tier" {
description = "The tier for the master instance."
type = string
default = "db-f1-micro"
}
variable "db_tier" {
description = "The tier for the primary SQL instance."
type = string
default = "db-f1-micro"
}
variable "file_tier" {
description = "The tier for the Filestore instance."
type = string
default = "BASIC_HDD"
}
variable "zone" {
type = string
description = "Zone target"
}
variable "disk_type" {
description = "GCE Boot/Attached Disk Type"
type = string
default = "pd-ssd"
}
variable "min_cpu" {
description = "GCE Minimum CPU Family"
type = string
default = "AMD Rome "
}
variable "image" {
description = "Path to GCE Image Type"
type = string
default = "windows-2019/windows-server-2019-dc-v20200908"
}
variable "vm_type" {
description = "The GCE machine type"
type = string
default = "n2d-highmem-8"
}
variable "availability_type" {
description = "The availability type for the master instance.This is only used to set up high availability for the PostgreSQL instance. Can be either `ZONAL` or `REGIONAL`."
type = string
default = "REGIONAL"
}
variable "backup_configuration" {
description = "The backup_configuration settings subblock for the database setings"
type = object({
enabled = bool
start_time = string
location = string
})
default = {
enabled = false
start_time = null
location = null
}
}
# variable "authorized_networks_a" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "71.164.77.198/32"
# }
# variable "authorized_networks_b" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
# variable "authorized_networks_c" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
variable "private_network" {
description = "Full path to private network ID"
type = string
default = "projects/esoteric-parsec-243510/global/networks/private-network"
}
variable "db_user" {
description = "The name of the DB user"
type = string
default = "postgres"
}
variable "user_name" {
description = "The name of the default user"
type = string
default = "default"
}
variable "user_password" {
description = "The password for the default user. If not set, a random one will be generated and available in the generated_user_password output variable."
type = string
default = ""
}
variable "additional_users" {
description = "A list of users to be created in your cluster"
type = list(object({
name = string
password = string
}))
default = []
}

View File

@@ -0,0 +1,32 @@
provider "google-beta" {
credentials = file("esoteric-parsec-243510-a8f93bb5a906.json")
project = var.project_id
region = var.region
zone = var.zone
}
resource "google_filestore_instance" "bt-filestore" {
provider = google-beta
name = "qseow-files"
zone = var.zone
tier = var.file_tier
project = var.project_id
file_shares {
capacity_gb = 1024
name = "qlikshare"
# nfs_export_options {
# ip_ranges = ["0.0.0.0/0"]
# access_mode = "READ_WRITE"
# squash_mode = "NO_ROOT_SQUASH"
# anon_uid = 0
# anon_gid = 0
# }
}
networks {
network = "default"
modes = ["MODE_IPV4"]
}
}

View File

@@ -0,0 +1,17 @@
# Configure return values from google_sql_database_instance
# output "psql_ip_address" {
# value = google_sql_database_instance.qseow-psql.private_ip_address
# }
output "fs_instance_ip" {
value = google_filestore_instance.bt-filestore.networks[0].ip_addresses
}
output "fs_instance_name" {
value = google_filestore_instance.bt-filestore.name
}
# output "fs_instance_path" {
# value = google_filestore_instance.bt-filestore.fileShares.name
# }

View File

@@ -0,0 +1,17 @@
{
"project_id": "esoteric-parsec-243510",
"region": "europe-west1",
"zone": "europe-west1-d",
"private_network": "projects/esoteric-parsec-243510/global/networks/default",
"database_version": "POSTGRES_9_6",
"db_tier": "db-g1-small",
"file_tier": "BASIC_HDD",
"vm_type": "e2-highmem-4",
"min_cpu": "Intel Skylake",
"image": "gce-uefi-images/windows-2019",
"disk_type": "pd-ssd",
"availability_type": "REGIONAL",
"db_user": "postgres",
"user_name": "qlikadmin",
"user_password": "Qlik1234!"
}

View File

@@ -0,0 +1,128 @@
variable "project_id" {
type = string
description = "The project ID to manage the Cloud SQL resources"
}
variable "database_version" {
description = "The database version to use"
type = string
}
variable "region" {
type = string
description = "GCP Region"
default = "us-central1"
}
variable "db_tier" {
description = "The tier for the primary SQL instance."
type = string
default = "db-f1-micro"
}
variable "file_tier" {
description = "The tier for the Filestore instance."
type = string
default = "BASIC_HDD"
}
variable "zone" {
type = string
description = "Zone target"
}
variable "disk_type" {
description = "GCE Boot/Attached Disk Type"
type = string
default = "pd-ssd"
}
variable "min_cpu" {
description = "GCE Minimum CPU Family"
type = string
default = "AMD Rome "
}
variable "image" {
description = "Path to GCE Image Type"
type = string
default = "windows-2019/windows-server-2019-dc-v20200908"
}
variable "vm_type" {
description = "The GCE machine type"
type = string
default = "n2d-highmem-8"
}
variable "availability_type" {
description = "The availability type for the master instance.This is only used to set up high availability for the PostgreSQL instance. Can be either `ZONAL` or `REGIONAL`."
type = string
default = "REGIONAL"
}
variable "backup_configuration" {
description = "The backup_configuration settings subblock for the database setings"
type = object({
enabled = bool
start_time = string
location = string
})
default = {
enabled = false
start_time = null
location = null
}
}
# variable "authorized_networks_a" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "71.164.77.198/32"
# }
# variable "authorized_networks_b" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
# variable "authorized_networks_c" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
variable "private_network" {
description = "Full path to private network ID"
type = string
default = "projects/esoteric-parsec-243510/global/networks/private-network"
}
variable "user_name" {
description = "The name of the default user"
type = string
default = "default"
}
variable "db_user" {
description = "The name of the DB user"
type = string
default = "postgres"
}
variable "user_password" {
description = "The password for the default user. If not set, a random one will be generated and available in the generated_user_password output variable."
type = string
default = ""
}
variable "additional_users" {
description = "A list of users to be created in your cluster"
type = list(object({
name = string
password = string
}))
default = []
}

View File

@@ -0,0 +1,22 @@
terraform {
required_version = ">= 0.12"
}
provider "google" {
version = "3.10.0"
credentials = file("esoteric-parsec-243510-a8f93bb5a906.json")
project = var.project
region = var.region
zone = var.zone
}
data "google_compute_instance_group" "geo" {
name = "GeoAnalyticsServer"
zone = var.zone
}
# Create random ID for VM suffix
resource "random_id" "vm_suffix" {
byte_length = 2
}

View File

@@ -0,0 +1,9 @@
# Configure return values from google_sql_database_instance
output "psql_ip_address" {
value = google_sql_database_instance.qseow-psql.private_ip_address
}
output "psql_instance_name" {
value = google_sql_database_instance.qseow-psql.connection_name
}

View File

@@ -0,0 +1,92 @@
variable "project_id" {
type = string
description = "The project ID to manage the Cloud SQL resources"
}
variable "database_version" {
description = "The database version to use"
type = string
}
variable "region" {
type = string
description = "GCP Region"
default = "us-central1"
}
variable "tier" {
description = "The tier for the master instance."
type = string
default = "db-f1-micro"
}
variable "zone" {
type = string
description = "Zone target"
}
variable "availability_type" {
description = "The availability type for the master instance.This is only used to set up high availability for the PostgreSQL instance. Can be either `ZONAL` or `REGIONAL`."
type = string
default = "REGIONAL"
}
variable "backup_configuration" {
description = "The backup_configuration settings subblock for the database setings"
type = object({
enabled = bool
start_time = string
location = string
})
default = {
enabled = false
start_time = null
location = null
}
}
# variable "authorized_networks_a" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "71.164.77.198/32"
# }
# variable "authorized_networks_b" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
# variable "authorized_networks_c" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
variable "private_network" {
description = "Full path to private network ID"
type = string
default = "projects/esoteric-parsec-243510/global/networks/private-network"
}
variable "user_name" {
description = "The name of the default user"
type = string
default = "default"
}
variable "user_password" {
description = "The password for the default user. If not set, a random one will be generated and available in the generated_user_password output variable."
type = string
default = ""
}
variable "additional_users" {
description = "A list of users to be created in your cluster"
type = list(object({
name = string
password = string
}))
default = []
}

View File

@@ -0,0 +1,4 @@
#!/bin/bash
terraform state rm google_sql_user.users
terraform destroy $@ -auto-approve

View File

@@ -0,0 +1,62 @@
### Main TF - split pSQL to a module
##
provider "google-beta" {
credentials = file("esoteric-parsec-243510-a8f93bb5a906.json")
project = var.project_id
region = var.region
zone = var.zone
}
# Create random ID for DB suffix
resource "random_id" "db_suffix" {
byte_length = 2
}
# Create res for Cloud SQL DB create
resource "google_sql_database_instance" "qseow-psql" {
provider = google-beta
name = "qseow-psql-${random_id.db_suffix.hex}"
project = var.project_id
region = var.region
database_version = var.database_version
settings {
tier = var.db_tier
availability_type = var.availability_type
backup_configuration {
enabled = "true"
}
ip_configuration {
ipv4_enabled = false
private_network = var.private_network
}
}
}
# Configure postgres admin user
## Note that the SQL instance cannot be rm'd without removing the TFState for
## the SQL user (TF/PostgreSQL race condition)
#
## Use "./destroy.sh" instead of "terraform destroy"
resource "google_sql_user" "users" {
provider = google-beta
instance = google_sql_database_instance.qseow-psql.name
name = var.db_user
password = var.user_password
project = var.project_id
depends_on = [google_sql_database_instance.qseow-psql]
}
# Execute stored SQL file, prep pSQL for Qlik Sense
resource "null_resource" "db_setup" {
provisioner "local-exec" {
command = "PGPASSWORD=${google_sql_user.users.password} /usr/bin/psql -h ${google_sql_database_instance.qseow-psql.private_ip_address} -Upostgres --dbname=postgres < qseow_db_setup.sql"
}
depends_on = [google_sql_database_instance.qseow-psql, google_sql_user.users]
}

View File

@@ -0,0 +1,9 @@
# Configure return values from google_sql_database_instance
output "psql_ip_address" {
value = google_sql_database_instance.qseow-psql.private_ip_address
}
output "psql_instance_name" {
value = google_sql_database_instance.qseow-psql.connection_name
}

View File

@@ -0,0 +1,39 @@
CREATE DATABASE "QSR" ENCODING = 'UTF8';
CREATE DATABASE "QSMQ" ENCODING = 'UTF8';
CREATE DATABASE "Licenses" ENCODING = 'UTF8';
CREATE DATABASE "SenseServices" ENCODING = 'UTF8';
CREATE DATABASE "QLogs" ENCODING = 'UTF8';
CREATE ROLE "qliksenserepository" WITH LOGIN NOINHERIT NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION VALID UNTIL 'infinity';
ALTER ROLE "qliksenserepository" WITH ENCRYPTED PASSWORD 'Qlik1234!';
GRANT "qliksenserepository" TO postgres;
ALTER DATABASE "QSR" OWNER TO "qliksenserepository";
ALTER DATABASE "SenseServices" OWNER TO "qliksenserepository";
ALTER DATABASE "QSMQ" OWNER TO "qliksenserepository";
ALTER DATABASE "Licenses" OWNER TO qliksenserepository;
GRANT TEMPORARY, CONNECT ON DATABASE "QSMQ" TO PUBLIC;
GRANT ALL ON DATABASE "QSMQ" TO postgres;
GRANT CREATE ON DATABASE "QSMQ" TO "qliksenserepository";
GRANT TEMPORARY, CONNECT ON DATABASE "SenseServices" TO PUBLIC;
GRANT ALL ON DATABASE "SenseServices" TO postgres;
GRANT CREATE ON DATABASE "SenseServices" TO "qliksenserepository";
GRANT TEMPORARY, CONNECT ON DATABASE "Licenses" TO PUBLIC;
GRANT ALL ON DATABASE "Licenses" TO postgres;
GRANT CREATE ON DATABASE "Licenses" TO qliksenserepository;
CREATE ROLE qlogs_users WITH NOLOGIN NOINHERIT NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION VALID UNTIL 'infinity';
CREATE ROLE qlogs_reader WITH LOGIN NOINHERIT NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION VALID UNTIL 'infinity';
CREATE ROLE qlogs_writer WITH LOGIN NOINHERIT NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION VALID UNTIL 'infinity';
ALTER ROLE qlogs_reader WITH ENCRYPTED PASSWORD 'Qlik1234!';
ALTER ROLE qlogs_writer WITH ENCRYPTED PASSWORD 'Qlik1234!';
GRANT qlogs_users TO qlogs_reader;
GRANT qlogs_users TO qlogs_writer;
ALTER DATABASE "QLogs" OWNER TO qlogs_writer; --sets qlogs_writer as an owner of QLogs database
SELECT * FROM pg_settings WHERE name = 'max_connections';

View File

@@ -0,0 +1,17 @@
{
"project_id": "esoteric-parsec-243510",
"region": "europe-west1",
"zone": "europe-west1-d",
"private_network": "projects/esoteric-parsec-243510/global/networks/default",
"database_version": "POSTGRES_9_6",
"db_tier": "db-g1-small",
"file_tier": "BASIC_HDD",
"vm_type": "e2-highmem-4",
"min_cpu": "Intel Skylake",
"image": "gce-uefi-images/windows-2019",
"disk_type": "pd-ssd",
"availability_type": "REGIONAL",
"db_user": "postgres",
"user_name": "qlikadmin",
"user_password": "Qlik1234!"
}

View File

@@ -0,0 +1,128 @@
variable "project_id" {
type = string
description = "The project ID to manage the Cloud SQL resources"
}
variable "database_version" {
description = "The database version to use"
type = string
}
variable "region" {
type = string
description = "GCP Region"
default = "us-central1"
}
variable "db_tier" {
description = "The tier for the primary SQL instance."
type = string
default = "db-f1-micro"
}
variable "file_tier" {
description = "The tier for the Filestore instance."
type = string
default = "BASIC_HDD"
}
variable "zone" {
type = string
description = "Zone target"
}
variable "disk_type" {
description = "GCE Boot/Attached Disk Type"
type = string
default = "pd-ssd"
}
variable "min_cpu" {
description = "GCE Minimum CPU Family"
type = string
default = "AMD Rome "
}
variable "image" {
description = "Path to GCE Image Type"
type = string
default = "windows-2019/windows-server-2019-dc-v20200908"
}
variable "vm_type" {
description = "The GCE machine type"
type = string
default = "n2d-highmem-8"
}
variable "availability_type" {
description = "The availability type for the master instance.This is only used to set up high availability for the PostgreSQL instance. Can be either `ZONAL` or `REGIONAL`."
type = string
default = "REGIONAL"
}
variable "backup_configuration" {
description = "The backup_configuration settings subblock for the database setings"
type = object({
enabled = bool
start_time = string
location = string
})
default = {
enabled = false
start_time = null
location = null
}
}
# variable "authorized_networks_a" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "71.164.77.198/32"
# }
# variable "authorized_networks_b" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
# variable "authorized_networks_c" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
variable "private_network" {
description = "Full path to private network ID"
type = string
default = "projects/esoteric-parsec-243510/global/networks/private-network"
}
variable "db_user" {
description = "The name of the DB user"
type = string
default = "postgres"
}
variable "user_name" {
description = "The name of the default user"
type = string
default = "default"
}
variable "user_password" {
description = "The password for the default user. If not set, a random one will be generated and available in the generated_user_password output variable."
type = string
default = ""
}
variable "additional_users" {
description = "A list of users to be created in your cluster"
type = list(object({
name = string
password = string
}))
default = []
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0"?>
<SharedPersistenceConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DbUserName>qliksenserepository</DbUserName>
<DbUserPassword>Qlik1234!</DbUserPassword>
<DbHost>10.54.242.47</DbHost>
<DbPort>5432</DbPort>
<RootDir>\\10.219.178.210\qlikshare</RootDir>
<StaticContentRootDir>\\10.219.178.210\qlikshare\StaticContent</StaticContentRootDir>
<ArchivedLogsDir>\\10.219.178.210\qlikshare\ArchivedLogs</ArchivedLogsDir>
<AppsDir>\\10.219.178.210\qlikshare\Apps</AppsDir>
<!-- <CreateCluster>true</CreateCluster> -->
<InstallLocalDb>false</InstallLocalDb>
<ConfigureDbListener>false</ConfigureDbListener>
<ListenAddresses>*</ListenAddresses>
<IpRange>0.0.0.0/0,::/0</IpRange>
<MaxConnections>100</MaxConnections>
<JoinCluster>true</JoinCluster>
<ConfigureLogging>true</ConfigureLogging>
<SetupLocalLoggingDb>false</SetupLocalLoggingDb>
<QLogsWriterPassword>Qlik1234!</QLogsWriterPassword>
<QLogsReaderPassword>Qlik1234!</QLogsReaderPassword>
<QLogsHostname>10.54.242.47</QLogsHostname>
<QLogsPort>5432</QLogsPort>
</SharedPersistenceConfiguration>

View File

@@ -0,0 +1,74 @@
terraform {
required_version = ">= 0.12"
}
provider "google-beta" {
credentials = file("esoteric-parsec-243510-a8f93bb5a906.json")
project = var.project_id
region = var.region
zone = var.zone
}
# Create random ID for VM suffix
resource "random_id" "vm_suffix" {
byte_length = 2
}
resource "google_compute_disk" "dataRim" {
provider = google-beta
name = "rim-datadisk-${random_id.vm_suffix.hex}"
type = var.disk_type
zone = var.zone
# labels = {
# environment = "dev"
# }
size = 50
}
resource "google_compute_instance" "rim" {
provider = google-beta
name = "rim-${random_id.vm_suffix.hex}"
machine_type = var.vm_type
# min_cpu_platform commented out during testing - e2 instances do not support
# min_cpu_platform = var.min_cpu
zone = var.zone
# hostname = "central-${random_id.vm_suffix.hex}"
# tags = ["foo", "bar"]
# timeouts {
# create = "60m"
# delete = "2h"
# }
boot_disk {
initialize_params {
image = var.image
}
}
attached_disk {
source = google_compute_disk.dataRim.name
}
# lifecycle {
# ignore_changes = [attached_disk]
# }
network_interface {
network = "default"
access_config {
network_tier = "STANDARD"
}
}
metadata = {
windows-startup-script-url = "gs://qliksense/scripts/bootstrap.ps1"
}
service_account {
email = "terraform@esoteric-parsec-243510.iam.gserviceaccount.com"
scopes = ["cloud-platform"]
}
}

View File

@@ -0,0 +1,21 @@
# Configure return values from google_sql_database_instance
# output "psql_ip_address" {
# value = google_sql_database_instance.qseow-psql.private_ip_address
# }
output "rim_name" {
value = google_compute_instance.rim.name
}
output "rim_ext_ip" {
value = google_compute_instance.rim.network_interface[0].access_config[0].nat_ip
}
output "rim_int_ip" {
value = google_compute_instance.rim.network_interface[0].network_ip
}
# output "serial_out" {
# value = data.google_compute_instance_serial_port.serial.contents
# }

View File

@@ -0,0 +1,17 @@
{
"project_id": "esoteric-parsec-243510",
"region": "europe-west1",
"zone": "europe-west1-d",
"private_network": "projects/esoteric-parsec-243510/global/networks/default",
"database_version": "POSTGRES_9_6",
"db_tier": "db-g1-small",
"file_tier": "BASIC_HDD",
"vm_type": "e2-highmem-4",
"min_cpu": "Intel Skylake",
"image": "gce-uefi-images/windows-2019",
"disk_type": "pd-ssd",
"availability_type": "REGIONAL",
"db_user": "postgres",
"user_name": "qlikadmin",
"user_password": "Qlik1234!"
}

View File

@@ -0,0 +1,134 @@
variable "project_id" {
type = string
description = "The project ID to manage the Cloud SQL resources"
}
variable "database_version" {
description = "The database version to use"
type = string
}
variable "region" {
type = string
description = "GCP Region"
default = "us-central1"
}
variable "tier" {
description = "The tier for the master instance."
type = string
default = "db-f1-micro"
}
variable "db_tier" {
description = "The tier for the primary SQL instance."
type = string
default = "db-f1-micro"
}
variable "file_tier" {
description = "The tier for the Filestore instance."
type = string
default = "BASIC_HDD"
}
variable "zone" {
type = string
description = "Zone target"
}
variable "disk_type" {
description = "GCE Boot/Attached Disk Type"
type = string
default = "pd-ssd"
}
variable "min_cpu" {
description = "GCE Minimum CPU Family"
type = string
default = "AMD Rome "
}
variable "image" {
description = "Path to GCE Image Type"
type = string
default = "windows-2019/windows-server-2019-dc-v20200908"
}
variable "vm_type" {
description = "The GCE machine type"
type = string
default = "n2d-highmem-8"
}
variable "availability_type" {
description = "The availability type for the master instance.This is only used to set up high availability for the PostgreSQL instance. Can be either `ZONAL` or `REGIONAL`."
type = string
default = "REGIONAL"
}
variable "backup_configuration" {
description = "The backup_configuration settings subblock for the database setings"
type = object({
enabled = bool
start_time = string
location = string
})
default = {
enabled = false
start_time = null
location = null
}
}
# variable "authorized_networks_a" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "71.164.77.198/32"
# }
# variable "authorized_networks_b" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
# variable "authorized_networks_c" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
variable "private_network" {
description = "Full path to private network ID"
type = string
default = "projects/esoteric-parsec-243510/global/networks/private-network"
}
variable "db_user" {
description = "The name of the DB user"
type = string
default = "postgres"
}
variable "user_name" {
description = "The name of the default user"
type = string
default = "default"
}
variable "user_password" {
description = "The password for the default user. If not set, a random one will be generated and available in the generated_user_password output variable."
type = string
default = ""
}
variable "additional_users" {
description = "A list of users to be created in your cluster"
type = list(object({
name = string
password = string
}))
default = []
}

View File

@@ -0,0 +1,57 @@
#!/usr/bin/env pwsh
#
if ($env:computername -like "central-*") {
exit 0
}
Write-Host "------------------------------------------------------------"
Write-Host " Adding Rim to Cluster "
Write-Host "------------------------------------------------------------"
$config = ( Read-GcsObject -Bucket "qliksense" -ObjectName "scripts/config.json" | ConvertFrom-Json )
# $centralNode = "central-84fe"
$centralNode = $config.cenName
$newNode = ($env:COMPUTERNAME).ToLower()
# $newNode = "rim-a8a3"
$qsAdminUser = $config.qsAdminUser
$qlikID = "$centralNode\$qsAdminUser"
$svcPwd = "Qlik1234!"
$secPwd = ConvertTo-SecureString -AsPlainText $svcPwd -Force
$secCred = New-Object System.Management.Automation.PSCredential -ArgumentList $qlikID, $secPwd
$qsConn = New-PSSession -ComputerName $centralNode
Invoke-Command -Session $qsConn -ScriptBlock { Get-ChildItem -Path cert:\CurrentUser\My `
| Where-Object { $_.Issuer -like "*$using:centralNode*" } `
| Connect-Qlik -computername https://"$using:centralNode":4242 -Username $using:qlikID | Out-Null
}
# Read-GcsObject -Bucket "qliksense" -ObjectName "certs/rim/client.pfx" -OutFile $deploy_path\certs\rim\client.pfx -Force
# Import-PfxCertificate -FilePath $deploy_path\certs\rim\client.pfx -CertStoreLocation Cert:\CurrentUser\My -Exportable
Invoke-Command -Session $qsConn -ScriptBlock { `
$proxyId = (Get-QlikVirtualProxy -full | Where-Object description -like "Central*").id}
#TODO: Read existing whitelist as array, add new node to list and then re-write new list.
Invoke-Command -Session $qsConn -ScriptBlock { `
Update-QlikVirtualProxy -id $proxyId -websocketCrossOriginWhiteList "$using:newNode", "$using:centralNode" | Out-Null
}
Invoke-Command -Session $qsConn -ScriptBlock { `
$password = New-QlikNode -hostname $using:newNode -name $using:newNode -nodePurpose Both -engineEnabled -proxyEnabled;
$foo = @{__pwd = "$password" }
}
$foo = Invoke-Command -Session $qsConn -ScriptBlock { $foo }
Invoke-WebRequest -Uri "http://localhost:4570/certificateSetup" -Method Post -Body $foo -credential $secCred
# Config Engine for better NFS Support, restart Engine to read new value
Set-Content -Path C:\ProgramData\Qlik\Sense\Engine\Settings.ini -Value "[Settings 7]`r`nMapNetworkDrives=1"
Restart-Service QlikSenseEngineService -Force
# Tag the GCE metadata that the Node has been in initialized.
Set-GceInstance -Name ($env:computername).ToLower() -Zone $config.zone -AddTag "joined-cluster"
# Close the remote PS session
Remove-PSSession $qsConn

View File

@@ -0,0 +1,129 @@
#!/usr/bin/env pwsh
#
## Intended to be executed in a GitOps pipeline on the new GCE resource by remote-exec in TF
## or as a startup script via Metadata key windows-startup-script-url
##
# Format and mount data disk
Write-Host "------------------------------------------------------------"
Write-Host " Create Data drive "
Write-Host "------------------------------------------------------------"
Get-Disk |
Where-Object partitionstyle -eq 'raw' |
Initialize-Disk -PartitionStyle GPT -PassThru |
New-Partition -DriveLetter E -UseMaximumSize |
Format-Volume -FileSystem NTFS -NewFileSystemLabel 'Data' -Confirm:$false
if (! (Test-Path E:\)) {
Write-Error "Drive not found"
exit 1
}
Write-Host "------------------------------------------------------------"
Write-Host " Create Local Accounts and add to Administrators Group "
Write-Host "------------------------------------------------------------"
if (!(Get-LocalUser -Name qservice -ErrorAction Ignore)) {
$password = ConvertTo-SecureString -String 'Qlik1234!' -AsPlainText -Force
New-LocalUser `
-Name 'qservice' `
-Password $password `
-PasswordNeverExpires `
-UserMayNotChangePassword
}
if (!(Get-LocalUser -Name qlikadmin -ErrorAction Ignore)) {
$password = ConvertTo-SecureString -String 'Qlik1234!' -AsPlainText -Force
New-LocalUser `
-Name 'qlikadmin' `
-Password $password `
-PasswordNeverExpires `
-UserMayNotChangePassword
}
Add-LocalGroupMember -Group "Administrators" -Member "qservice", "qlikadmin"
Write-Host "------------------------------------------------------------"
Write-Host " Copy tooling from Cloud Storage Bucket "
Write-Host "------------------------------------------------------------"
# $config = ( Read-GcsObject -Bucket "qliksense" -ObjectName "scripts/config.json" | ConvertFrom-Json )
$deploy_path = "E:\deploy"
if (! (Test-Path $deploy_path)) {
New-Item -ItemType Directory -Path $deploy_path
New-Item -ItemType Directory -Path $deploy_path\binaries
}
gsutil -m cp -r gs://qliksense/scripts $deploy_path\
gsutil -m cp gs://qliksense/binaries/Qlik_Sense* $deploy_path\binaries\
gsutil -m cp gs://qliksense/binaries/firefox_latest.exe $deploy_path\binaries\
Unblock-File -Path $deploy_path\binaries\*
Unblock-File -Path $deploy_path\scripts\*
REG ADD HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v ConsentPromptBehaviorAdmin /t REG_DWORD /d 0 /f
# WinRM Connects
New-Item -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation -Name AllowFreshCredentialsWhenNTLMOnly -Force
New-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation\AllowFreshCredentialsWhenNTLMOnly -Name 1 -Value * -PropertyType String
Set-Item WSMan:localhost\client\trustedhosts -value * -Force
Write-Host "------------------------------------------------------------"
Write-Host " Import PS Modules "
Write-Host "------------------------------------------------------------"
# Installing Qlik-CLI
# Write-Host "Downloading Qlik-Cli from Github and importing the Module"
# Invoke-WebRequest "https://raw.githubusercontent.com/ahaydon/Qlik-Cli/master/Qlik-Cli.psm1" -OutFile $temp\Qlik-Cli.psm1
# New-Item -ItemType directory -Path C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Qlik-Cli -force
# Move-Item $temp\Qlik-Cli.psm1 C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Qlik-Cli\ -force
# Import-Module Qlik-Cli.psm1
# Export-QlikCertificate -machineNames rim -includeSecretsKey -exportFormat Windows
Get-PackageProvider -Name NuGet -ForceBootstrap
Install-Module Qlik-CLI -Force
Write-Host "------------------------------------------------------------"
Write-Host " Firefox "
Write-Host "------------------------------------------------------------"
# Expand-Archive -Path $deploy_path\binaries\ps7.zip -DestinationPath $deploy_path\binaries\ps7 -Force
# Start-Sleep -Seconds 120
Invoke-Command -ScriptBlock { Start-Process -FilePath "$deploy_path\binaries\firefox_latest.exe" -verb runAs -ArgumentList "/s" -Wait -PassThru } | Out-Null
Invoke-Command -ScriptBlock { Start-Process -FilePath "$deploy_path\binaries\vscode_stable.exe" -verb runAs -ArgumentList "/VERYSILENT /NORESTART /MERGETASKS=!runcode" -Wait -PassThru } | Out-Null
Write-Host "------------------------------------------------------------"
Write-Host " Create QSEoW FW Rule "
Write-Host "------------------------------------------------------------"
New-NetFirewallRule -DisplayName "Qlik Sense" -Direction Inbound -LocalPort 80, 443, 3090, 4000, 4432, 4242, 4244, 4444, 4248, 4993, 4994, 5353, 5355, 5555, 5556 -Protocol TCP -Action Allow -ea Stop | Out-Null
# Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False
#### Enable NFS Client, set Anon user to UID:GID 0 == root. Restart service.
Write-Host "------------------------------------------------------------"
Write-Host " Installing NFS Client "
Write-Host "------------------------------------------------------------"
Install-WindowsFeature -Name NFS-Client
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default" `
-Name "AnonymousUid" -Value "0" -PropertyType DWORD
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default" `
-Name "AnonymousGid" -Value "0" -PropertyType DWORD
nfsadmin client stop
nfsadmin client start
# REG ADD HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v ConsentPromptBehaviorAdmin /t REG_DWORD /d 5 /f
# HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
# Create "RunOnce" registry key to install QSEoW
# New-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce' -Name 'Run' -Value 'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe -noprofile -sta -WindowStyle Hidden -executionpolicy unrestricted -file E:\deploy\scripts\qsInstall.ps1'
# Tag the GCE metadata that the Node has been bootstrapped, remove startup-script URL.
Set-GceInstance -Name ($env:computername).ToLower() -Zone $config.zone -AddTag "bootstrapped"
Set-GceInstance -Name ($env:computername).ToLower() -Zone $config.zone -RemoveMetadata "windows-startup-script-url"
Restart-Computer
Exit 0

View File

@@ -0,0 +1,15 @@
[
{
"dbUserName": "qliksenserepository",
"dbUserPassword": "Qlik1234!",
"dbInstanceIp": "10.54.242.56",
"dbPort": "5432",
"fsInstanceIp": "10.247.74.186",
"fsShareName": "qlikshare",
"deployPath": "E:\\deploy",
"cenName": "central-aa6d",
"qsAdminUser": "qlikadmin",
"qsSvcUser": "qservice",
"zone": "europe-west1-d"
}
]

View File

@@ -0,0 +1,147 @@
#!/usr/bin/env pwsh
#
## Intended to be executed in a GitOps pipeline on the new GCE resource by remote-exec in TF
## or as a startup script via Metadata key windows-startup-script-url
##
$config = ( Read-GcsObject -Bucket "qliksense" -ObjectName "scripts/config.json" | ConvertFrom-Json )
$qsAdminUser = $config.qsAdminUser
$centralNode = ($env:COMPUTERNAME).ToLower()
$qlikID = "$centralNode\$qsAdminUser"
$deploy_path = $config.deployPath
#### Functions
Function waitProxy {
$statusCode = 0
Write-Host "Waiting for Proxy..."
while ($StatusCode -ne 200) {
try { $statusCode = (Invoke-WebRequest https://$($env:COMPUTERNAME)/qps/user -usebasicParsing).statusCode }
Catch {
Write-Host "Proxy unavailable - retrying in 30s"
Start-Sleep -s 30
}
}
Write-Host "Proxy responding on $env:COMPUTERNAME, status code: $statusCode"
}
# TODO: Archive XMLs to GCS Bucket?
Function writeXmlCen {
$xmlsettings = New-Object System.Xml.XmlWriterSettings
$xmlsettings.Indent = $true
$xmlsettings.IndentChars = " "
$filePath = "$deploy_path\scripts\cen.xml" # Set the File Name
$xml = [System.XML.XmlWriter]::Create($filePath, $Null) # Create The Document
$xml.WriteStartDocument() # Write the XML Decleration
$xml.WriteStartElement("SharedPersistenceConfiguration") # Write Root Element
$xml.WriteAttributeString("xmlns", "xsi", "", "http://www.w3.org/2001/XMLSchema-instance")
$xml.WriteAttributeString("xmlns", "xsd", "", "http://www.w3.org/2001/XMLSchema")
$xml.WriteElementString("DbUserName", "$($config.dbUserName)") # <-- Begin writing the XML file
$xml.WriteElementString("DbUserPassword", "$($config.dbUserPassword)")
$xml.WriteElementString("DbHost", "$($config.dbInstanceIp)")
$xml.WriteElementString("DbPort", "$($config.dbPort)")
$xml.WriteElementString("RootDir", "$("\\" + $config.fsInstanceIp + "\" + $config.fsShareName)")
$xml.WriteElementString("StaticContentRootDir", "$("\\" + $config.fsInstanceIp + "\" + $config.fsShareName)" + "\StaticContent")
$xml.WriteElementString("ArchivedLogsDir", "$("\\" + $config.fsInstanceIp + "\" + $config.fsShareName)" + "\ArchivedLogs")
$xml.WriteElementString("AppsDir", "$("\\" + $config.fsInstanceIp + "\" + $config.fsShareName)" + "\Apps")
$xml.WriteElementString("CreateCluster", "true")
$xml.WriteElementString("InstallLocalDb", "false")
$xml.WriteElementString("ConfigureDbListener", "false")
$xml.WriteElementString("ListenAddresses", "*")
$xml.WriteElementString("IpRange", "0.0.0.0/0")
$xml.WriteEndElement | Out-Null # <-- Closing RootElement
$xml.WriteEndDocument() | Out-Null # End the XML Document
$xml.Finalize | Out-Null # Finish The Document
$xml.Flush | Out-Null
$xml.Close() | Out-Null
}
# xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
Function writeXmlRim {
$xmlsettings = New-Object System.Xml.XmlWriterSettings
$xmlsettings.Indent = $true
$xmlsettings.IndentChars = " "
$filePath = "$deploy_path\scripts\rim.xml" # Set the File Name
$xml = [System.XML.XmlWriter]::Create($filePath, $Null) # Create The Document
$xml.WriteStartDocument() # Write the XML Decleration
$xml.WriteStartElement("SharedPersistenceConfiguration") # Write Root Element
$xml.WriteAttributeString("xmlns", "xsi", "", "http://www.w3.org/2001/XMLSchema-instance")
$xml.WriteAttributeString("xmlns", "xsd", "", "http://www.w3.org/2001/XMLSchema")
$xml.WriteElementString("DbUserName", "$($config.dbUserName)") # <-- Begin writing the XML file
$xml.WriteElementString("DbUserPassword", "$($config.dbUserPassword)")
$xml.WriteElementString("DbHost", "$($config.dbInstanceIp)")
$xml.WriteElementString("DbPort", "$($config.dbPort)")
$xml.WriteElementString("RootDir", "$("\\" + $config.fsInstanceIp + "\" + $config.fsShareName)")
$xml.WriteElementString("StaticContentRootDir", "$("\\" + $config.fsInstanceIp + "\" + $config.fsShareName)" + "\StaticContent")
$xml.WriteElementString("ArchivedLogsDir", "$("\\" + $config.fsInstanceIp + "\" + $config.fsShareName)" + "\ArchivedLogs")
$xml.WriteElementString("AppsDir", "$("\\" + $config.fsInstanceIp + "\" + $config.fsShareName)" + "\Apps")
$xml.WriteElementString("JoinCluster", "true")
$xml.WriteElementString("InstallLocalDb", "false")
$xml.WriteElementString("ConfigureDbListener", "false")
$xml.WriteElementString("ListenAddresses", "*")
$xml.WriteElementString("IpRange", "0.0.0.0/0")
$xml.WriteEndElement | Out-Null # <-- Closing RootElement
$xml.WriteEndDocument() | Out-Null # End the XML Document
$xml.Finalize | Out-Null # Finish The Document
$xml.Flush | Out-Null
$xml.Close() | Out-Null
}
#### Launch silent install
Write-Host "------------------------------------------------------------"
Write-Host " Installing QSEoW "
Write-Host "------------------------------------------------------------"
if ($env:computername -like "central-*") {
writeXmlCen
Invoke-Command -ScriptBlock { Start-Process -FilePath "$deploy_path\binaries\Qlik_Sense_setup.exe" -ArgumentList "-s -log $deploy_path\deploy.log accepteula=1 skipvalidation=1 installdir=$deploy_path\Qlik dbpassword=Qlik1234! hostname=$($env:computername) userwithdomain=$($env:computername)\qservice password=Qlik1234! bundleinstall=dashboard,visualization spc=$deploy_path\scripts\cen.xml" -Wait -PassThru } | Out-Null
Set-Item WSMan:localhost\client\trustedhosts -value * -Force
# Connect to Qlik Sense
waitProxy
Get-ChildItem -Path cert:\CurrentUser\My | Where-Object { $_.Issuer -like "*$centralNode*" } | Connect-Qlik -computername https://"$centralNode":4242 -Username $qlikID | Out-Null
# Set the SLK
$license = (Get-Content $deploy_path\scripts\license.json -raw) | ConvertFrom-Json
Set-QlikLicense -key "$($license.signed.key)" -name "$($license.signed.name)" -organization "$($license.signed.organization)" | Out-Null
If (Test-Path "$deploy_path\binaries\Qlik_Sense_update.exe") {
Write-Host "------------------------------------------------------------"
Write-Host " Installing QSEoW Patch "
Write-Host "------------------------------------------------------------"
Invoke-Command -ScriptBlock { Start-Process -FilePath "$deploy_path\binaries\Qlik_Sense_Update.exe" -ArgumentList "install" -Wait -Passthru } | Out-Null
}
# Config Engine for better NFS Support, restart Engine to read new value
Set-Content -Path C:\ProgramData\Qlik\Sense\Engine\Settings.ini -Value "[Settings 7]`r`nMapNetworkDrives=1"
Restart-Service QlikSenseEngineService -Force
# Tag the GCE metadata that the Node has been in initialized.
Set-GceInstance -Name ($env:computername).ToLower() -Zone $config.zone -AddTag "qseInstalled"
}
else {
writeXmlRim
Invoke-Command -ScriptBlock { Start-Process -FilePath "$deploy_path\binaries\Qlik_Sense_setup.exe" -ArgumentList "-s -log $deploy_path\deploy.log accepteula=1 skipvalidation=1 installdir=$deploy_path\Qlik dbpassword=Qlik1234! hostname=$($env:computername) userwithdomain=$($env:computername)\qservice password=Qlik1234! bundleinstall=dashboard,visualization spc=$deploy_path\scripts\rim.xml" -Wait -PassThru } | Out-Null
Set-Item WSMan:localhost\client\trustedhosts -value * -Force
If (Test-Path "$deploy_path\binaries\Qlik_Sense_update.exe") {
Write-Host "------------------------------------------------------------"
Write-Host " Installing QSEoW Patch "
Write-Host "------------------------------------------------------------"
Invoke-Command -ScriptBlock { Start-Process -FilePath "$deploy_path\binaries\Qlik_Sense_Update.exe" `
-ArgumentList "install" -Wait -Passthru } | Out-Null
}
Invoke-Command -ScriptBlock { Start-Process C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe "-noprofile -sta -WindowStyle Hidden -executionpolicy unrestricted -file $deploy_path\scripts\addRim.ps1" -Wait -PassThru } | Out-Null
# Tag the GCE metadata that the Node has been initialized into the cluster
Set-GceInstance -Name ($env:computername).ToLower() -Zone $config.zone -AddTag "qse-installed"
}

View File

@@ -0,0 +1,48 @@
REG ADD HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v ConsentPromptBehaviorAdmin /t REG_DWORD /d 0 /f
Invoke-Command -ScriptBlock {Start-Process -FilePath "E:\deploy\binaries\Qlik_Sense_setup.exe" -verb runAs -ArgumentList "-s -log E:\deploy\deploy.log accepteula=1 installdir=E:\deploy\Qlik dbpassword=Qlik1234! hostname=$($env:computername) userwithdomain=$($env:computername)\qservice password=Qlik1234! bundleinstall=dashboard,visualization spc=E:\deploy\scripts\cen.xml" -Wait -PassThru} | Out-Null
$license = (Get-Content E:\scripts\license.json -raw) | ConvertFrom-Json
Set-QlikLicense -key "$($license.signed.key)" -name "$($license.signed.name)" -organization "$($license.signed.organization)"| Out-Null
# qlikSenseProfessionalAccess
New-GcsObject -Bucket "qliksense" -Folder "C:\ProgramData\Qlik\Sense\Repository\Exported Certificates" -Force
Write-GcsObject -Bucket "qliksense" -File "C:\ProgramData\Qlik\Sense\Repository\Exported Certificates\rim\client.pfx" -ObjectName "certs/rim/client.pfx"
REG ADD HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v ConsentPromptBehaviorAdmin /t REG_DWORD /d 5 /f
########################################
# 6 $license = (Get-Content $deploy_path\scripts\license.json -raw) | ConvertFrom-Json
# 7 $centralNode = ($env:COMPUTERNAME).ToLower()
# 9 $qlikID = ".\qlikadmin"
# 10 $deploy_path = "E:\deploy"
# 14 Set-QlikLicense -key "$($license.signed.key)" -name "$($license.signed.name)" -organization "$($license.signed....
# 18 Export-QlikCertificate -machineNames rim -includeSecretsKey -exportFormat Windows
# 1 $deploy_path = "E:\deploy"
# 2 $centralNode = ($env:COMPUTERNAME).ToLower()
# 3 $qlikID = ".\qlikadmin"
# Write-GcsObject -Bucket "qliksense" -File "C:\ProgramData\Qlik\Sense\Repository\Exported Certificates\rim\client.pfx" -ObjectName "certs/rim/client.pfx"
# Installing Qlik-CLI
# Write-Host "Downloading Qlik-Cli from Github and importing the Module"
# Invoke-WebRequest "https://raw.githubusercontent.com/ahaydon/Qlik-Cli/master/Qlik-Cli.psm1" -OutFile $temp\Qlik-Cli.psm1
# New-Item -ItemType directory -Path C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Qlik-Cli -force
# Move-Item $temp\Qlik-Cli.psm1 C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Qlik-Cli\ -force
# Import-Module Qlik-Cli.psm1
# Export-QlikCertificate -machineNames rim -includeSecretsKey -exportFormat Windows
Read-GcsObject -Bucket "qliksense" -ObjectName "certs/rim/client.pfx" -OutFile $deploy_path\certs\rim\client.pfx -Force
Import-PfxCertificate -FilePath $deploy_path\certs\rim\client.pfx -CertStoreLocation Cert:\CurrentUser\My -Exportable
$nodeid = Get-QlikNode -filter "(name eq $newNode)"
Invoke-QlikGet -path /qrs/servernoderegistration/start/$($nodeid.id)
# Invoke-WebRequest -Uri https://github.com/PowerShell/PowerShell/releases/download/v7.0.3/PowerShell-7.0.3-win-x64.zip -OutFile $deploy_path\binaries\ps7.zip
# Invoke-WebRequest -Uri https://aka.ms/win32-x64-user-stable -Outfile $deploy_path\binaries\vscode_stable.exe
# Invoke-WebRequest -Uri "https://download.mozilla.org/?product=firefox-latest-ssl&os=win64&lang=en-US" -Outfile $deploy_path\binaries\firefox_latest.exe

View File

@@ -0,0 +1,39 @@
$config = ( Read-GcsObject -Bucket "qliksense" -ObjectName "scripts/config.json" | ConvertFrom-Json )
$qsAdminUser = $config.qsAdminUser
$centralNode = ($env:COMPUTERNAME).ToLower()
$qlikID = "$centralNode\$qsAdminUser"
$deploy_path = $config.deployPath
#### Functions
Function writeXmlCen {
$xmlsettings = New-Object System.Xml.XmlWriterSettings
$xmlsettings.Indent = $true
$xmlsettings.IndentChars = " "
$filePath = "$deploy_path\scripts\cen.xml" # Set the File Name
$xml = [System.XML.XmlWriter]::Create($filePath, $Null) # Create The Document
$xml.WriteStartDocument() # Write the XML Decleration
$xml.WriteStartElement("SharedPersistenceConfiguration") # Write Root Element
$xml.WriteAttributeString("xmlns", "xsi", "", "http://www.w3.org/2001/XMLSchema-instance")
$xml.WriteAttributeString("xmlns", "xsd", "", "http://www.w3.org/2001/XMLSchema")
$xml.WriteElementString("DbUserName", "$($config.dbUserName)") # <-- Begin writing the XML file
$xml.WriteElementString("DbUserPassword", "$($config.dbUserPassword)")
$xml.WriteElementString("DbHost", "$($config.dbInstanceIp)")
$xml.WriteElementString("DbPort", "$($config.dbPort)")
$xml.WriteElementString("RootDir", "$("\\" + $config.fsInstanceIp + "\" + $config.fsShareName)")
$xml.WriteElementString("StaticContentRootDir", "$("\\" + $config.fsInstanceIp + "\" + $config.fsShareName)" + "\StaticContent")
$xml.WriteElementString("ArchivedLogsDir", "$("\\" + $config.fsInstanceIp + "\" + $config.fsShareName)" + "\ArchivedLogs")
$xml.WriteElementString("AppsDir", "$("\\" + $config.fsInstanceIp + "\" + $config.fsShareName)" + "\Apps")
$xml.WriteElementString("CreateCluster", "true")
$xml.WriteElementString("InstallLocalDb", "false")
$xml.WriteElementString("ConfigureDbListener", "false")
$xml.WriteElementString("ListenAddresses", "*")
$xml.WriteElementString("IpRange", "0.0.0.0/0")
$xml.WriteEndElement | Out-Null # <-- Closing RootElement
$xml.WriteEndDocument() | Out-Null # End the XML Document
$xml.Finalize | Out-Null # Finish The Document
$xml.Flush | Out-Null
$xml.Close() | Out-Null
}
writeXmlCen

View File

@@ -0,0 +1,367 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.43.0 (0)
-->
<!-- Title: %3 Pages: 1 -->
<svg width="2796pt" height="476pt"
viewBox="0.00 0.00 2796.37 476.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 472)">
<title>%3</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-472 2792.37,-472 2792.37,4 -4,4"/>
<!-- [root] google_compute_disk.data (expand) -->
<g id="node1" class="node">
<title>[root] google_compute_disk.data (expand)</title>
<polygon fill="none" stroke="black" points="2046,-180 1842,-180 1842,-144 2046,-144 2046,-180"/>
<text text-anchor="middle" x="1944" y="-158.3" font-family="Times,serif" font-size="14.00">google_compute_disk.data</text>
</g>
<!-- [root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;] -->
<g id="node3" class="node">
<title>[root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;]</title>
<polygon fill="none" stroke="black" points="1589,-108 1212.29,-90 1589,-72 1965.71,-90 1589,-108"/>
<text text-anchor="middle" x="1589" y="-86.3" font-family="Times,serif" font-size="14.00">provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;]</text>
</g>
<!-- [root] google_compute_disk.data (expand)&#45;&gt;[root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;] -->
<g id="edge1" class="edge">
<title>[root] google_compute_disk.data (expand)&#45;&gt;[root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;]</title>
<path fill="none" stroke="black" d="M1857.61,-143.97C1799.91,-132.59 1724.6,-117.74 1668.4,-106.66"/>
<polygon fill="black" stroke="black" points="1668.98,-103.2 1658.5,-104.7 1667.63,-110.07 1668.98,-103.2"/>
</g>
<!-- [root] random_id.vm_suffix (expand) -->
<g id="node5" class="node">
<title>[root] random_id.vm_suffix (expand)</title>
<polygon fill="none" stroke="black" points="2376,-108 2212,-108 2212,-72 2376,-72 2376,-108"/>
<text text-anchor="middle" x="2294" y="-86.3" font-family="Times,serif" font-size="14.00">random_id.vm_suffix</text>
</g>
<!-- [root] google_compute_disk.data (expand)&#45;&gt;[root] random_id.vm_suffix (expand) -->
<g id="edge2" class="edge">
<title>[root] google_compute_disk.data (expand)&#45;&gt;[root] random_id.vm_suffix (expand)</title>
<path fill="none" stroke="black" d="M2029.17,-143.97C2081.46,-133.51 2148.43,-120.11 2201.94,-109.41"/>
<polygon fill="black" stroke="black" points="2202.65,-112.84 2211.77,-107.45 2201.28,-105.98 2202.65,-112.84"/>
</g>
<!-- [root] var.disk_type -->
<g id="node10" class="node">
<title>[root] var.disk_type</title>
<polygon fill="none" stroke="black" points="2088,-108 1984,-108 1984,-72 2094,-72 2094,-102 2088,-108"/>
<polyline fill="none" stroke="black" points="2088,-108 2088,-102 "/>
<polyline fill="none" stroke="black" points="2094,-102 2088,-102 "/>
<text text-anchor="middle" x="2039" y="-86.3" font-family="Times,serif" font-size="14.00">var.disk_type</text>
</g>
<!-- [root] google_compute_disk.data (expand)&#45;&gt;[root] var.disk_type -->
<g id="edge3" class="edge">
<title>[root] google_compute_disk.data (expand)&#45;&gt;[root] var.disk_type</title>
<path fill="none" stroke="black" d="M1967.48,-143.7C1979.56,-134.8 1994.45,-123.82 2007.52,-114.2"/>
<polygon fill="black" stroke="black" points="2009.81,-116.85 2015.79,-108.1 2005.66,-111.22 2009.81,-116.85"/>
</g>
<!-- [root] google_compute_instance.default (expand) -->
<g id="node2" class="node">
<title>[root] google_compute_instance.default (expand)</title>
<polygon fill="none" stroke="black" points="2152,-252 1898,-252 1898,-216 2152,-216 2152,-252"/>
<text text-anchor="middle" x="2025" y="-230.3" font-family="Times,serif" font-size="14.00">google_compute_instance.default</text>
</g>
<!-- [root] google_compute_instance.default (expand)&#45;&gt;[root] google_compute_disk.data (expand) -->
<g id="edge4" class="edge">
<title>[root] google_compute_instance.default (expand)&#45;&gt;[root] google_compute_disk.data (expand)</title>
<path fill="none" stroke="black" d="M2004.98,-215.7C1994.87,-206.97 1982.46,-196.24 1971.48,-186.75"/>
<polygon fill="black" stroke="black" points="1973.65,-183.99 1963.79,-180.1 1969.07,-189.29 1973.65,-183.99"/>
</g>
<!-- [root] var.image -->
<g id="node11" class="node">
<title>[root] var.image</title>
<polygon fill="none" stroke="black" points="2144,-180 2064,-180 2064,-144 2150,-144 2150,-174 2144,-180"/>
<polyline fill="none" stroke="black" points="2144,-180 2144,-174 "/>
<polyline fill="none" stroke="black" points="2150,-174 2144,-174 "/>
<text text-anchor="middle" x="2107" y="-158.3" font-family="Times,serif" font-size="14.00">var.image</text>
</g>
<!-- [root] google_compute_instance.default (expand)&#45;&gt;[root] var.image -->
<g id="edge5" class="edge">
<title>[root] google_compute_instance.default (expand)&#45;&gt;[root] var.image</title>
<path fill="none" stroke="black" d="M2045.27,-215.7C2055.5,-206.97 2068.06,-196.24 2079.18,-186.75"/>
<polygon fill="black" stroke="black" points="2081.63,-189.26 2086.96,-180.1 2077.09,-183.94 2081.63,-189.26"/>
</g>
<!-- [root] var.vm_type -->
<g id="node19" class="node">
<title>[root] var.vm_type</title>
<polygon fill="none" stroke="black" points="2265.5,-180 2168.5,-180 2168.5,-144 2271.5,-144 2271.5,-174 2265.5,-180"/>
<polyline fill="none" stroke="black" points="2265.5,-180 2265.5,-174 "/>
<polyline fill="none" stroke="black" points="2271.5,-174 2265.5,-174 "/>
<text text-anchor="middle" x="2220" y="-158.3" font-family="Times,serif" font-size="14.00">var.vm_type</text>
</g>
<!-- [root] google_compute_instance.default (expand)&#45;&gt;[root] var.vm_type -->
<g id="edge6" class="edge">
<title>[root] google_compute_instance.default (expand)&#45;&gt;[root] var.vm_type</title>
<path fill="none" stroke="black" d="M2072.7,-215.88C2099.95,-206.09 2134.3,-193.77 2162.97,-183.47"/>
<polygon fill="black" stroke="black" points="2164.22,-186.74 2172.45,-180.07 2161.86,-180.15 2164.22,-186.74"/>
</g>
<!-- [root] var.project_id -->
<g id="node14" class="node">
<title>[root] var.project_id</title>
<polygon fill="none" stroke="black" points="1520.5,-36 1413.5,-36 1413.5,0 1526.5,0 1526.5,-30 1520.5,-36"/>
<polyline fill="none" stroke="black" points="1520.5,-36 1520.5,-30 "/>
<polyline fill="none" stroke="black" points="1526.5,-30 1520.5,-30 "/>
<text text-anchor="middle" x="1470" y="-14.3" font-family="Times,serif" font-size="14.00">var.project_id</text>
</g>
<!-- [root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;]&#45;&gt;[root] var.project_id -->
<g id="edge21" class="edge">
<title>[root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;]&#45;&gt;[root] var.project_id</title>
<path fill="none" stroke="black" d="M1562,-73.12C1546,-63.7 1525.47,-51.63 1507.87,-41.28"/>
<polygon fill="black" stroke="black" points="1509.37,-38.1 1498.98,-36.04 1505.82,-44.13 1509.37,-38.1"/>
</g>
<!-- [root] var.region -->
<g id="node15" class="node">
<title>[root] var.region</title>
<polygon fill="none" stroke="black" points="1627.5,-36 1544.5,-36 1544.5,0 1633.5,0 1633.5,-30 1627.5,-36"/>
<polyline fill="none" stroke="black" points="1627.5,-36 1627.5,-30 "/>
<polyline fill="none" stroke="black" points="1633.5,-30 1627.5,-30 "/>
<text text-anchor="middle" x="1589" y="-14.3" font-family="Times,serif" font-size="14.00">var.region</text>
</g>
<!-- [root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;]&#45;&gt;[root] var.region -->
<g id="edge22" class="edge">
<title>[root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;]&#45;&gt;[root] var.region</title>
<path fill="none" stroke="black" d="M1589,-71.7C1589,-63.98 1589,-54.71 1589,-46.11"/>
<polygon fill="black" stroke="black" points="1592.5,-46.1 1589,-36.1 1585.5,-46.1 1592.5,-46.1"/>
</g>
<!-- [root] var.zone -->
<g id="node20" class="node">
<title>[root] var.zone</title>
<polygon fill="none" stroke="black" points="1722,-36 1652,-36 1652,0 1728,0 1728,-30 1722,-36"/>
<polyline fill="none" stroke="black" points="1722,-36 1722,-30 "/>
<polyline fill="none" stroke="black" points="1728,-30 1722,-30 "/>
<text text-anchor="middle" x="1690" y="-14.3" font-family="Times,serif" font-size="14.00">var.zone</text>
</g>
<!-- [root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;]&#45;&gt;[root] var.zone -->
<g id="edge23" class="edge">
<title>[root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;]&#45;&gt;[root] var.zone</title>
<path fill="none" stroke="black" d="M1612.17,-72.94C1625.41,-63.76 1642.24,-52.1 1656.86,-41.97"/>
<polygon fill="black" stroke="black" points="1658.95,-44.78 1665.17,-36.21 1654.96,-39.03 1658.95,-44.78"/>
</g>
<!-- [root] provider[&quot;registry.terraform.io/hashicorp/random&quot;] -->
<g id="node4" class="node">
<title>[root] provider[&quot;registry.terraform.io/hashicorp/random&quot;]</title>
<polygon fill="none" stroke="black" points="2294,-36 1943.6,-18 2294,0 2644.4,-18 2294,-36"/>
<text text-anchor="middle" x="2294" y="-14.3" font-family="Times,serif" font-size="14.00">provider[&quot;registry.terraform.io/hashicorp/random&quot;]</text>
</g>
<!-- [root] random_id.vm_suffix (expand)&#45;&gt;[root] provider[&quot;registry.terraform.io/hashicorp/random&quot;] -->
<g id="edge25" class="edge">
<title>[root] random_id.vm_suffix (expand)&#45;&gt;[root] provider[&quot;registry.terraform.io/hashicorp/random&quot;]</title>
<path fill="none" stroke="black" d="M2294,-71.7C2294,-63.98 2294,-54.71 2294,-46.11"/>
<polygon fill="black" stroke="black" points="2297.5,-46.1 2294,-36.1 2290.5,-46.1 2297.5,-46.1"/>
</g>
<!-- [root] var.additional_users -->
<g id="node6" class="node">
<title>[root] var.additional_users</title>
<polygon fill="none" stroke="black" points="154,-324 0,-324 0,-288 160,-288 160,-318 154,-324"/>
<polyline fill="none" stroke="black" points="154,-324 154,-318 "/>
<polyline fill="none" stroke="black" points="160,-318 154,-318 "/>
<text text-anchor="middle" x="80" y="-302.3" font-family="Times,serif" font-size="14.00">var.additional_users</text>
</g>
<!-- [root] var.availability_type -->
<g id="node7" class="node">
<title>[root] var.availability_type</title>
<polygon fill="none" stroke="black" points="332,-324 178,-324 178,-288 338,-288 338,-318 332,-324"/>
<polyline fill="none" stroke="black" points="332,-324 332,-318 "/>
<polyline fill="none" stroke="black" points="338,-318 332,-318 "/>
<text text-anchor="middle" x="258" y="-302.3" font-family="Times,serif" font-size="14.00">var.availability_type</text>
</g>
<!-- [root] var.backup_configuration -->
<g id="node8" class="node">
<title>[root] var.backup_configuration</title>
<polygon fill="none" stroke="black" points="545.5,-324 356.5,-324 356.5,-288 551.5,-288 551.5,-318 545.5,-324"/>
<polyline fill="none" stroke="black" points="545.5,-324 545.5,-318 "/>
<polyline fill="none" stroke="black" points="551.5,-318 545.5,-318 "/>
<text text-anchor="middle" x="454" y="-302.3" font-family="Times,serif" font-size="14.00">var.backup_configuration</text>
</g>
<!-- [root] var.database_version -->
<g id="node9" class="node">
<title>[root] var.database_version</title>
<polygon fill="none" stroke="black" points="730.5,-324 569.5,-324 569.5,-288 736.5,-288 736.5,-318 730.5,-324"/>
<polyline fill="none" stroke="black" points="730.5,-324 730.5,-318 "/>
<polyline fill="none" stroke="black" points="736.5,-318 730.5,-318 "/>
<text text-anchor="middle" x="653" y="-302.3" font-family="Times,serif" font-size="14.00">var.database_version</text>
</g>
<!-- [root] var.min_cpu -->
<g id="node12" class="node">
<title>[root] var.min_cpu</title>
<polygon fill="none" stroke="black" points="850,-324 754,-324 754,-288 856,-288 856,-318 850,-324"/>
<polyline fill="none" stroke="black" points="850,-324 850,-318 "/>
<polyline fill="none" stroke="black" points="856,-318 850,-318 "/>
<text text-anchor="middle" x="805" y="-302.3" font-family="Times,serif" font-size="14.00">var.min_cpu</text>
</g>
<!-- [root] var.private_network -->
<g id="node13" class="node">
<title>[root] var.private_network</title>
<polygon fill="none" stroke="black" points="1027.5,-324 874.5,-324 874.5,-288 1033.5,-288 1033.5,-318 1027.5,-324"/>
<polyline fill="none" stroke="black" points="1027.5,-324 1027.5,-318 "/>
<polyline fill="none" stroke="black" points="1033.5,-318 1027.5,-318 "/>
<text text-anchor="middle" x="954" y="-302.3" font-family="Times,serif" font-size="14.00">var.private_network</text>
</g>
<!-- [root] var.tier -->
<g id="node16" class="node">
<title>[root] var.tier</title>
<polygon fill="none" stroke="black" points="1114,-324 1052,-324 1052,-288 1120,-288 1120,-318 1114,-324"/>
<polyline fill="none" stroke="black" points="1114,-324 1114,-318 "/>
<polyline fill="none" stroke="black" points="1120,-318 1114,-318 "/>
<text text-anchor="middle" x="1086" y="-302.3" font-family="Times,serif" font-size="14.00">var.tier</text>
</g>
<!-- [root] var.user_name -->
<g id="node17" class="node">
<title>[root] var.user_name</title>
<polygon fill="none" stroke="black" points="1252,-324 1138,-324 1138,-288 1258,-288 1258,-318 1252,-324"/>
<polyline fill="none" stroke="black" points="1252,-324 1252,-318 "/>
<polyline fill="none" stroke="black" points="1258,-318 1252,-318 "/>
<text text-anchor="middle" x="1198" y="-302.3" font-family="Times,serif" font-size="14.00">var.user_name</text>
</g>
<!-- [root] var.user_password -->
<g id="node18" class="node">
<title>[root] var.user_password</title>
<polygon fill="none" stroke="black" points="1419.5,-324 1276.5,-324 1276.5,-288 1425.5,-288 1425.5,-318 1419.5,-324"/>
<polyline fill="none" stroke="black" points="1419.5,-324 1419.5,-318 "/>
<polyline fill="none" stroke="black" points="1425.5,-318 1419.5,-318 "/>
<text text-anchor="middle" x="1351" y="-302.3" font-family="Times,serif" font-size="14.00">var.user_password</text>
</g>
<!-- [root] meta.count&#45;boundary (EachMode fixup) -->
<g id="node21" class="node">
<title>[root] meta.count&#45;boundary (EachMode fixup)</title>
<ellipse fill="none" stroke="black" cx="1020" cy="-378" rx="222.86" ry="18"/>
<text text-anchor="middle" x="1020" y="-374.3" font-family="Times,serif" font-size="14.00">[root] meta.count&#45;boundary (EachMode fixup)</text>
</g>
<!-- [root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.additional_users -->
<g id="edge9" class="edge">
<title>[root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.additional_users</title>
<path fill="none" stroke="black" d="M812.53,-371.41C642.32,-365.1 395.02,-351.97 170.46,-324.09"/>
<polygon fill="black" stroke="black" points="170.82,-320.61 160.46,-322.84 169.94,-327.56 170.82,-320.61"/>
</g>
<!-- [root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.availability_type -->
<g id="edge10" class="edge">
<title>[root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.availability_type</title>
<path fill="none" stroke="black" d="M834.82,-367.92C701.95,-360.09 518.54,-346.62 348.6,-324.14"/>
<polygon fill="black" stroke="black" points="348.84,-320.64 338.47,-322.78 347.91,-327.57 348.84,-320.64"/>
</g>
<!-- [root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.backup_configuration -->
<g id="edge11" class="edge">
<title>[root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.backup_configuration</title>
<path fill="none" stroke="black" d="M888.44,-363.41C798.95,-353.79 677.6,-340.02 561.71,-324.21"/>
<polygon fill="black" stroke="black" points="561.97,-320.71 551.59,-322.82 561.02,-327.64 561.97,-320.71"/>
</g>
<!-- [root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.database_version -->
<g id="edge12" class="edge">
<title>[root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.database_version</title>
<path fill="none" stroke="black" d="M937.18,-361.2C880.62,-350.42 805.58,-336.1 746.82,-324.89"/>
<polygon fill="black" stroke="black" points="747.27,-321.42 736.79,-322.98 745.96,-328.29 747.27,-321.42"/>
</g>
<!-- [root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.min_cpu -->
<g id="edge13" class="edge">
<title>[root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.min_cpu</title>
<path fill="none" stroke="black" d="M969.05,-360.41C938.21,-350.37 898.7,-337.51 866.18,-326.92"/>
<polygon fill="black" stroke="black" points="866.92,-323.48 856.33,-323.71 864.76,-330.14 866.92,-323.48"/>
</g>
<!-- [root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.private_network -->
<g id="edge14" class="edge">
<title>[root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.private_network</title>
<path fill="none" stroke="black" d="M1003.69,-359.7C995.69,-351.22 985.93,-340.86 977.18,-331.58"/>
<polygon fill="black" stroke="black" points="979.53,-328.98 970.13,-324.1 974.44,-333.78 979.53,-328.98"/>
</g>
<!-- [root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.tier -->
<g id="edge15" class="edge">
<title>[root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.tier</title>
<path fill="none" stroke="black" d="M1036.31,-359.7C1044.31,-351.22 1054.07,-340.86 1062.82,-331.58"/>
<polygon fill="black" stroke="black" points="1065.56,-333.78 1069.87,-324.1 1060.47,-328.98 1065.56,-333.78"/>
</g>
<!-- [root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.user_name -->
<g id="edge16" class="edge">
<title>[root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.user_name</title>
<path fill="none" stroke="black" d="M1062.64,-360.23C1087.37,-350.51 1118.73,-338.17 1145.03,-327.83"/>
<polygon fill="black" stroke="black" points="1146.45,-331.03 1154.48,-324.12 1143.89,-324.52 1146.45,-331.03"/>
</g>
<!-- [root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.user_password -->
<g id="edge17" class="edge">
<title>[root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] var.user_password</title>
<path fill="none" stroke="black" d="M1095.52,-361.03C1146.43,-350.26 1213.66,-336.05 1266.37,-324.9"/>
<polygon fill="black" stroke="black" points="1267.31,-328.28 1276.37,-322.78 1265.86,-321.43 1267.31,-328.28"/>
</g>
<!-- [root] output.gce_external_ip (expand) -->
<g id="node22" class="node">
<title>[root] output.gce_external_ip (expand)</title>
<ellipse fill="none" stroke="black" cx="1632" cy="-306" rx="188.47" ry="18"/>
<text text-anchor="middle" x="1632" y="-302.3" font-family="Times,serif" font-size="14.00">[root] output.gce_external_ip (expand)</text>
</g>
<!-- [root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] output.gce_external_ip (expand) -->
<g id="edge7" class="edge">
<title>[root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] output.gce_external_ip (expand)</title>
<path fill="none" stroke="black" d="M1142.74,-362.96C1248.21,-350.9 1399.66,-333.58 1506.04,-321.41"/>
<polygon fill="black" stroke="black" points="1506.66,-324.86 1516.2,-320.25 1505.86,-317.9 1506.66,-324.86"/>
</g>
<!-- [root] output.gce_internal_ip (expand) -->
<g id="node23" class="node">
<title>[root] output.gce_internal_ip (expand)</title>
<ellipse fill="none" stroke="black" cx="2025" cy="-306" rx="186.57" ry="18"/>
<text text-anchor="middle" x="2025" y="-302.3" font-family="Times,serif" font-size="14.00">[root] output.gce_internal_ip (expand)</text>
</g>
<!-- [root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] output.gce_internal_ip (expand) -->
<g id="edge8" class="edge">
<title>[root] meta.count&#45;boundary (EachMode fixup)&#45;&gt;[root] output.gce_internal_ip (expand)</title>
<path fill="none" stroke="black" d="M1193.67,-366.69C1357.54,-356.7 1610.06,-340.66 1829,-324 1846.6,-322.66 1865.08,-321.17 1883.37,-319.64"/>
<polygon fill="black" stroke="black" points="1883.84,-323.11 1893.51,-318.79 1883.25,-316.14 1883.84,-323.11"/>
</g>
<!-- [root] output.gce_external_ip (expand)&#45;&gt;[root] google_compute_instance.default (expand) -->
<g id="edge18" class="edge">
<title>[root] output.gce_external_ip (expand)&#45;&gt;[root] google_compute_instance.default (expand)</title>
<path fill="none" stroke="black" d="M1716.79,-289.9C1776.12,-279.33 1855.8,-265.14 1919.27,-253.83"/>
<polygon fill="black" stroke="black" points="1920.09,-257.24 1929.32,-252.04 1918.86,-250.35 1920.09,-257.24"/>
</g>
<!-- [root] output.gce_internal_ip (expand)&#45;&gt;[root] google_compute_instance.default (expand) -->
<g id="edge19" class="edge">
<title>[root] output.gce_internal_ip (expand)&#45;&gt;[root] google_compute_instance.default (expand)</title>
<path fill="none" stroke="black" d="M2025,-287.7C2025,-279.98 2025,-270.71 2025,-262.11"/>
<polygon fill="black" stroke="black" points="2028.5,-262.1 2025,-252.1 2021.5,-262.1 2028.5,-262.1"/>
</g>
<!-- [root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;] (close) -->
<g id="node24" class="node">
<title>[root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;] (close)</title>
<ellipse fill="none" stroke="black" cx="2123" cy="-378" rx="328.44" ry="18"/>
<text text-anchor="middle" x="2123" y="-374.3" font-family="Times,serif" font-size="14.00">[root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;] (close)</text>
</g>
<!-- [root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;] (close)&#45;&gt;[root] google_compute_instance.default (expand) -->
<g id="edge20" class="edge">
<title>[root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;] (close)&#45;&gt;[root] google_compute_instance.default (expand)</title>
<path fill="none" stroke="black" d="M2177.3,-360.21C2194.32,-352.1 2211.2,-340.45 2221,-324 2229.19,-310.26 2230.73,-300.7 2221,-288 2210.23,-273.93 2177.68,-262.73 2142.13,-254.33"/>
<polygon fill="black" stroke="black" points="2142.56,-250.84 2132.04,-252.03 2141.01,-257.66 2142.56,-250.84"/>
</g>
<!-- [root] provider[&quot;registry.terraform.io/hashicorp/random&quot;] (close) -->
<g id="node25" class="node">
<title>[root] provider[&quot;registry.terraform.io/hashicorp/random&quot;] (close)</title>
<ellipse fill="none" stroke="black" cx="2479" cy="-234" rx="309.25" ry="18"/>
<text text-anchor="middle" x="2479" y="-230.3" font-family="Times,serif" font-size="14.00">[root] provider[&quot;registry.terraform.io/hashicorp/random&quot;] (close)</text>
</g>
<!-- [root] provider[&quot;registry.terraform.io/hashicorp/random&quot;] (close)&#45;&gt;[root] random_id.vm_suffix (expand) -->
<g id="edge24" class="edge">
<title>[root] provider[&quot;registry.terraform.io/hashicorp/random&quot;] (close)&#45;&gt;[root] random_id.vm_suffix (expand)</title>
<path fill="none" stroke="black" d="M2456.68,-215.87C2423.63,-190.5 2361.56,-142.85 2324.38,-114.32"/>
<polygon fill="black" stroke="black" points="2326.46,-111.5 2316.39,-108.19 2322.2,-117.05 2326.46,-111.5"/>
</g>
<!-- [root] root -->
<g id="node26" class="node">
<title>[root] root</title>
<ellipse fill="none" stroke="black" cx="2123" cy="-450" rx="58.49" ry="18"/>
<text text-anchor="middle" x="2123" y="-446.3" font-family="Times,serif" font-size="14.00">[root] root</text>
</g>
<!-- [root] root&#45;&gt;[root] meta.count&#45;boundary (EachMode fixup) -->
<g id="edge26" class="edge">
<title>[root] root&#45;&gt;[root] meta.count&#45;boundary (EachMode fixup)</title>
<path fill="none" stroke="black" d="M2066.4,-445.41C1907.84,-435.35 1454.23,-406.56 1199.37,-390.38"/>
<polygon fill="black" stroke="black" points="1199.46,-386.88 1189.26,-389.74 1199.02,-393.87 1199.46,-386.88"/>
</g>
<!-- [root] root&#45;&gt;[root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;] (close) -->
<g id="edge27" class="edge">
<title>[root] root&#45;&gt;[root] provider[&quot;registry.terraform.io/hashicorp/google&#45;beta&quot;] (close)</title>
<path fill="none" stroke="black" d="M2123,-431.7C2123,-423.98 2123,-414.71 2123,-406.11"/>
<polygon fill="black" stroke="black" points="2126.5,-406.1 2123,-396.1 2119.5,-406.1 2126.5,-406.1"/>
</g>
<!-- [root] root&#45;&gt;[root] provider[&quot;registry.terraform.io/hashicorp/random&quot;] (close) -->
<g id="edge28" class="edge">
<title>[root] root&#45;&gt;[root] provider[&quot;registry.terraform.io/hashicorp/random&quot;] (close)</title>
<path fill="none" stroke="black" d="M2181.47,-448.02C2267.64,-445.27 2422.58,-434.89 2460,-396 2494.22,-360.43 2490.47,-298.05 2484.72,-262.27"/>
<polygon fill="black" stroke="black" points="2488.1,-261.32 2482.91,-252.09 2481.21,-262.54 2488.1,-261.32"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -0,0 +1,19 @@
{
"bindings": [
{
"members": [
"user:jprdonnelly@gmail.com"
],
"role": "roles/iam.serviceAccountAdmin"
},
{
"members": [
"serviceAccount:593942668809-compute@developer.gserviceaccount.com",
"user:jprdonnelly@gmail.com"
],
"role": "roles/iam.serviceAccountUser"
}
],
"etag": "BwWvglMDG2Y=",
"version": 1
}

View File

@@ -0,0 +1,14 @@
bindings:
- members:
- user:jprdonnelly@gmail.com
role: roles/iam.serviceAccountAdmin
- members:
- serviceAccount:593942668809-compute@developer.gserviceaccount.com
- user:jprdonnelly@gmail.com
role: roles/iam.serviceAccountUser
- members:
- serviceAccount:593942668809-compute@developer.gserviceaccount.com
- user:jprdonnelly@gmail.com
role: roles/compute.instanceAdmin.v1
etag: BwWvglMDG2Y=
version: 1

View File

@@ -0,0 +1,107 @@
terraform {
required_version = ">= 0.12"
}
provider "google-beta" {
credentials = file("esoteric-parsec-243510-a8f93bb5a906.json")
project = var.project_id
region = var.region
zone = var.zone
}
# Create random ID for VM suffix
resource "random_id" "vm_suffix" {
byte_length = 2
}
resource "google_compute_disk" "dataCen" {
provider = google-beta
name = "central-datadisk-${random_id.vm_suffix.hex}"
type = var.disk_type
zone = var.zone
# labels = {
# environment = "dev"
# }
size = 50
}
resource "google_compute_instance" "central" {
provider = google-beta
name = "central-${random_id.vm_suffix.hex}"
machine_type = var.vm_type
# min_cpu_platform commented out during testing - e2 instances do not support
# min_cpu_platform = var.min_cpu
zone = var.zone
# hostname = "central-${random_id.vm_suffix.hex}"
# tags = ["foo", "bar"]
# timeouts {
# create = "60m"
# delete = "2h"
# }
boot_disk {
initialize_params {
image = var.image
}
}
attached_disk {
source = google_compute_disk.dataCen.name
}
# lifecycle {
# ignore_changes = [attached_disk]
# }
network_interface {
network = "default"
access_config {
network_tier = "STANDARD"
}
}
metadata = {
windows-startup-script-url = "gs://qliksense/scripts/bootstrap-cen.ps1"
}
service_account {
email = "terraform@esoteric-parsec-243510.iam.gserviceaccount.com"
scopes = ["cloud-platform"]
}
}
# data "google_compute_instance_serial_port" "serial" {
# provider = google-beta
# instance = google_compute_instance.central.name
# zone = var.zone
# port = 4
# }
# resource "local_file" "log" {
# filename = "${path.module}/tf-deploy.log"
# content = join("\n", "${data.google_compute_instance_serial_port.serial.contents}")
# }
# resource "null_resource" "bootstrap" {
# connection {
# type = "winrm"
# https = true
# insecure = true
# use_ntlm = true
# user = var.user_name
# password = var.user_password
# host = google_compute_instance.central.name
# timeout = "20m"
# }
# provisioner "remote-exec" {
# inline = [
# "powershell.exe -ExecutionPolicy Bypass -File E:\\deploy\\scripts\\win-nfs_client-install.ps1"
# ]
# }
# }

View File

@@ -0,0 +1,21 @@
# Configure return values from google_sql_database_instance
# output "psql_ip_address" {
# value = google_sql_database_instance.qseow-psql.private_ip_address
# }
output "gce_name" {
value = google_compute_instance.central.name
}
output "gce_external_ip" {
value = google_compute_instance.central.network_interface[0].access_config[0].nat_ip
}
output "gce_internal_ip" {
value = google_compute_instance.central.network_interface[0].network_ip
}
# output "serial_out" {
# value = data.google_compute_instance_serial_port.serial.contents
# }

View File

@@ -0,0 +1,14 @@
{
"project_id": "esoteric-parsec-243510",
"region": "europe-west1",
"zone": "europe-west1-d",
"private_network": "projects/esoteric-parsec-243510/global/networks/default",
"database_version": "POSTGRES_9_6",
"vm_type": "e2-highmem-4",
"min_cpu": "Intel Skylake",
"image": "gce-uefi-images/windows-2019",
"disk_type": "pd-ssd",
"availability_type": "REGIONAL",
"user_name": "qlikadmin",
"user_password": "Qlik1234!"
}

View File

@@ -0,0 +1,116 @@
variable "project_id" {
type = string
description = "The project ID to manage the Cloud SQL resources"
}
variable "database_version" {
description = "The database version to use"
type = string
}
variable "region" {
type = string
description = "GCP Region"
default = "us-central1"
}
variable "tier" {
description = "The tier for the master instance."
type = string
default = "db-f1-micro"
}
variable "zone" {
type = string
description = "Zone target"
}
variable "disk_type" {
description = "GCE Boot/Attached Disk Type"
type = string
default = "pd-ssd"
}
variable "min_cpu" {
description = "GCE Minimum CPU Family"
type = string
default = "AMD Rome "
}
variable "image" {
description = "Path to GCE Image Type"
type = string
default = "windows-2019/windows-server-2019-dc-v20200908"
}
variable "vm_type" {
description = "The GCE machine type"
type = string
default = "n2d-highmem-8"
}
variable "availability_type" {
description = "The availability type for the master instance.This is only used to set up high availability for the PostgreSQL instance. Can be either `ZONAL` or `REGIONAL`."
type = string
default = "REGIONAL"
}
variable "backup_configuration" {
description = "The backup_configuration settings subblock for the database setings"
type = object({
enabled = bool
start_time = string
location = string
})
default = {
enabled = false
start_time = null
location = null
}
}
# variable "authorized_networks_a" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "71.164.77.198/32"
# }
# variable "authorized_networks_b" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
# variable "authorized_networks_c" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
variable "private_network" {
description = "Full path to private network ID"
type = string
default = "projects/esoteric-parsec-243510/global/networks/private-network"
}
variable "user_name" {
description = "The name of the default user"
type = string
default = "default"
}
variable "user_password" {
description = "The password for the default user. If not set, a random one will be generated and available in the generated_user_password output variable."
type = string
default = ""
}
variable "additional_users" {
description = "A list of users to be created in your cluster"
type = list(object({
name = string
password = string
}))
default = []
}

View File

@@ -0,0 +1,32 @@
provider "google-beta" {
credentials = file("esoteric-parsec-243510-a8f93bb5a906.json")
project = var.project_id
region = var.region
zone = var.zone
}
resource "google_filestore_instance" "bt-filestore" {
provider = google-beta
name = "qseow-files"
zone = var.zone
tier = var.file_tier
project = var.project_id
file_shares {
capacity_gb = 1024
name = "qlikshare"
# nfs_export_options {
# ip_ranges = ["0.0.0.0/0"]
# access_mode = "READ_WRITE"
# squash_mode = "NO_ROOT_SQUASH"
# anon_uid = 0
# anon_gid = 0
# }
}
networks {
network = "default"
modes = ["MODE_IPV4"]
}
}

View File

@@ -0,0 +1,17 @@
# Configure return values from google_sql_database_instance
# output "psql_ip_address" {
# value = google_sql_database_instance.qseow-psql.private_ip_address
# }
output "fs_instance_ip" {
value = google_filestore_instance.bt-filestore.networks[0].ip_addresses
}
output "fs_instance_name" {
value = google_filestore_instance.bt-filestore.name
}
# output "fs_instance_path" {
# value = google_filestore_instance.bt-filestore.fileShares.name
# }

View File

@@ -0,0 +1,12 @@
{
"project_id": "esoteric-parsec-243510",
"region": "europe-west1",
"zone": "europe-west1-d",
"private_network": "projects/esoteric-parsec-243510/global/networks/default",
"database_version": "POSTGRES_9_6",
"db_tier": "db-g1-small",
"file_tier": "BASIC_HDD",
"availability_type": "REGIONAL",
"user_name": "qlikadmin",
"user_password": "Qlik1234!"
}

View File

@@ -0,0 +1,98 @@
variable "project_id" {
type = string
description = "The project ID to manage the Cloud SQL resources"
}
variable "database_version" {
description = "The database version to use"
type = string
}
variable "region" {
type = string
description = "GCP Region"
default = "us-central1"
}
variable "db_tier" {
description = "The tier for the primary SQL instance."
type = string
default = "db-f1-micro"
}
variable "file_tier" {
description = "The tier for the Filestore instance."
type = string
default = "BASIC_HDD"
}
variable "zone" {
type = string
description = "Zone target"
}
variable "availability_type" {
description = "The availability type for the master instance.This is only used to set up high availability for the PostgreSQL instance. Can be either `ZONAL` or `REGIONAL`."
type = string
default = "REGIONAL"
}
variable "backup_configuration" {
description = "The backup_configuration settings subblock for the database setings"
type = object({
enabled = bool
start_time = string
location = string
})
default = {
enabled = false
start_time = null
location = null
}
}
# variable "authorized_networks_a" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "71.164.77.198/32"
# }
# variable "authorized_networks_b" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
# variable "authorized_networks_c" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
variable "private_network" {
description = "Full path to private network ID"
type = string
default = "projects/esoteric-parsec-243510/global/networks/private-network"
}
variable "user_name" {
description = "The name of the default user"
type = string
default = "default"
}
variable "user_password" {
description = "The password for the default user. If not set, a random one will be generated and available in the generated_user_password output variable."
type = string
default = ""
}
variable "additional_users" {
description = "A list of users to be created in your cluster"
type = list(object({
name = string
password = string
}))
default = []
}

View File

@@ -0,0 +1,22 @@
terraform {
required_version = ">= 0.12"
}
provider "google" {
version = "3.10.0"
credentials = file("esoteric-parsec-243510-a8f93bb5a906.json")
project = var.project
region = var.region
zone = var.zone
}
data "google_compute_instance_group" "geo" {
name = "GeoAnalyticsServer"
zone = var.zone
}
# Create random ID for VM suffix
resource "random_id" "vm_suffix" {
byte_length = 2
}

View File

@@ -0,0 +1,9 @@
# Configure return values from google_sql_database_instance
output "psql_ip_address" {
value = google_sql_database_instance.qseow-psql.private_ip_address
}
output "psql_instance_name" {
value = google_sql_database_instance.qseow-psql.connection_name
}

View File

@@ -0,0 +1,92 @@
variable "project_id" {
type = string
description = "The project ID to manage the Cloud SQL resources"
}
variable "database_version" {
description = "The database version to use"
type = string
}
variable "region" {
type = string
description = "GCP Region"
default = "us-central1"
}
variable "tier" {
description = "The tier for the master instance."
type = string
default = "db-f1-micro"
}
variable "zone" {
type = string
description = "Zone target"
}
variable "availability_type" {
description = "The availability type for the master instance.This is only used to set up high availability for the PostgreSQL instance. Can be either `ZONAL` or `REGIONAL`."
type = string
default = "REGIONAL"
}
variable "backup_configuration" {
description = "The backup_configuration settings subblock for the database setings"
type = object({
enabled = bool
start_time = string
location = string
})
default = {
enabled = false
start_time = null
location = null
}
}
# variable "authorized_networks_a" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "71.164.77.198/32"
# }
# variable "authorized_networks_b" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
# variable "authorized_networks_c" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
variable "private_network" {
description = "Full path to private network ID"
type = string
default = "projects/esoteric-parsec-243510/global/networks/private-network"
}
variable "user_name" {
description = "The name of the default user"
type = string
default = "default"
}
variable "user_password" {
description = "The password for the default user. If not set, a random one will be generated and available in the generated_user_password output variable."
type = string
default = ""
}
variable "additional_users" {
description = "A list of users to be created in your cluster"
type = list(object({
name = string
password = string
}))
default = []
}

View File

@@ -0,0 +1,4 @@
#!/bin/bash
terraform state rm google_sql_user.users
terraform destroy $@ -auto-approve

View File

@@ -0,0 +1,60 @@
### Main TF - split pSQL to a module
##
provider "google" {
credentials = file("esoteric-parsec-243510-a8f93bb5a906.json")
project = var.project_id
region = var.region
zone = var.zone
}
# Create random ID for DB suffix
resource "random_id" "db_suffix" {
byte_length = 2
}
# Create res for Cloud SQL DB create
resource "google_sql_database_instance" "qseow-psql" {
name = "qseow-psql-${random_id.db_suffix.hex}"
project = var.project_id
region = var.region
database_version = var.database_version
settings {
tier = var.db_tier
availability_type = var.availability_type
backup_configuration {
enabled = "true"
}
ip_configuration {
ipv4_enabled = false
private_network = var.private_network
}
}
}
# Configure postgres admin user
## Note that the SQL instance cannot be rm'd without removing the TFState for
## the SQL user (TF/PostgreSQL race condition)
#
## Use "./destroy.sh" instead of "terraform destroy"
resource "google_sql_user" "users" {
instance = google_sql_database_instance.qseow-psql.name
name = var.db_user
password = var.user_password
project = var.project_id
depends_on = [google_sql_database_instance.qseow-psql]
}
# Execute stored SQL file, prep pSQL for Qlik Sense
resource "null_resource" "db_setup" {
provisioner "local-exec" {
command = "PGPASSWORD=${google_sql_user.users.password} /usr/bin/psql -h ${google_sql_database_instance.qseow-psql.private_ip_address} -Upostgres --dbname=postgres < qseow_db_setup.sql"
}
depends_on = [google_sql_database_instance.qseow-psql, google_sql_user.users]
}

View File

@@ -0,0 +1,9 @@
# Configure return values from google_sql_database_instance
output "psql_ip_address" {
value = google_sql_database_instance.qseow-psql.private_ip_address
}
output "psql_instance_name" {
value = google_sql_database_instance.qseow-psql.connection_name
}

View File

@@ -0,0 +1,37 @@
CREATE DATABASE "QSR" ENCODING = 'UTF8';
CREATE DATABASE "QSMQ" ENCODING = 'UTF8';
CREATE DATABASE "Licenses" ENCODING = 'UTF8';
CREATE DATABASE "SenseServices" ENCODING = 'UTF8';
CREATE DATABASE "QLogs" ENCODING = 'UTF8';
CREATE ROLE "qliksenserepository" WITH LOGIN NOINHERIT NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION VALID UNTIL 'infinity';
ALTER ROLE "qliksenserepository" WITH ENCRYPTED PASSWORD 'Qlik1234!';
GRANT "qliksenserepository" TO postgres;
ALTER DATABASE "QSR" OWNER TO "qliksenserepository";
ALTER DATABASE "SenseServices" OWNER TO "qliksenserepository";
ALTER DATABASE "QSMQ" OWNER TO "qliksenserepository";
ALTER DATABASE "Licenses" OWNER TO qliksenserepository;
GRANT TEMPORARY, CONNECT ON DATABASE "QSMQ" TO PUBLIC;
GRANT ALL ON DATABASE "QSMQ" TO postgres;
GRANT CREATE ON DATABASE "QSMQ" TO "qliksenserepository";
GRANT TEMPORARY, CONNECT ON DATABASE "SenseServices" TO PUBLIC;
GRANT ALL ON DATABASE "SenseServices" TO postgres;
GRANT CREATE ON DATABASE "SenseServices" TO "qliksenserepository";
GRANT TEMPORARY, CONNECT ON DATABASE "Licenses" TO PUBLIC;
GRANT ALL ON DATABASE "Licenses" TO postgres;
GRANT CREATE ON DATABASE "Licenses" TO qliksenserepository;
CREATE ROLE qlogs_users WITH NOLOGIN NOINHERIT NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION VALID UNTIL 'infinity';
CREATE ROLE qlogs_reader WITH LOGIN NOINHERIT NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION VALID UNTIL 'infinity';
CREATE ROLE qlogs_writer WITH LOGIN NOINHERIT NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION VALID UNTIL 'infinity';
ALTER ROLE qlogs_reader WITH ENCRYPTED PASSWORD 'Qlik1234!';
ALTER ROLE qlogs_writer WITH ENCRYPTED PASSWORD 'Qlik1234!';
GRANT qlogs_users TO qlogs_reader;
GRANT qlogs_users TO qlogs_writer;
ALTER DATABASE "QLogs" OWNER TO qlogs_writer; --sets qlogs_writer as an owner of QLogs database

View File

@@ -0,0 +1,5 @@
project = "esoteric-parsec-243510"
region = "us-central1"
zone = "us-central1-a"
aclCIDR = "71.164.77.198/32"
postgresPwd = "Qlik1234!"

View File

@@ -0,0 +1,13 @@
{
"project_id": "esoteric-parsec-243510",
"region": "europe-west1",
"zone": "europe-west1-d",
"private_network": "projects/esoteric-parsec-243510/global/networks/default",
"database_version": "POSTGRES_9_6",
"db_tier": "db-g1-small",
"file_tier": "BASIC_HDD",
"availability_type": "REGIONAL",
"db_user": "postgres",
"user_name": "qlikadmin",
"user_password": "Qlik1234!"
}

View File

@@ -0,0 +1,104 @@
variable "project_id" {
type = string
description = "The project ID to manage the Cloud SQL resources"
}
variable "database_version" {
description = "The database version to use"
type = string
}
variable "region" {
type = string
description = "GCP Region"
default = "us-central1"
}
variable "db_tier" {
description = "The tier for the primary SQL instance."
type = string
default = "db-f1-micro"
}
variable "file_tier" {
description = "The tier for the Filestore instance."
type = string
default = "BASIC_HDD"
}
variable "zone" {
type = string
description = "Zone target"
}
variable "availability_type" {
description = "The availability type for the master instance.This is only used to set up high availability for the PostgreSQL instance. Can be either `ZONAL` or `REGIONAL`."
type = string
default = "REGIONAL"
}
variable "backup_configuration" {
description = "The backup_configuration settings subblock for the database setings"
type = object({
enabled = bool
start_time = string
location = string
})
default = {
enabled = false
start_time = null
location = null
}
}
# variable "authorized_networks_a" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "71.164.77.198/32"
# }
# variable "authorized_networks_b" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
# variable "authorized_networks_c" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
variable "private_network" {
description = "Full path to private network ID"
type = string
default = "projects/esoteric-parsec-243510/global/networks/private-network"
}
variable "db_user" {
description = "The name of the DB user"
type = string
default = "postgres"
}
variable "user_name" {
description = "The name of the default user"
type = string
default = "default"
}
variable "user_password" {
description = "The password for the default user. If not set, a random one will be generated and available in the generated_user_password output variable."
type = string
default = ""
}
variable "additional_users" {
description = "A list of users to be created in your cluster"
type = list(object({
name = string
password = string
}))
default = []
}

View File

@@ -0,0 +1,20 @@
terraform {
required_providers {
google = {
source = "hashicorp/google"
}
postgresql = {
source = "terraform-providers/postgresql"
}
random = {
source = "hashicorp/random"
}
template = {
source = "hashicorp/template"
}
null = {
source = "hashicorp/null"
}
}
required_version = ">= 0.13"
}

View File

@@ -0,0 +1,106 @@
terraform {
required_version = ">= 0.12"
}
provider "google-beta" {
credentials = file("esoteric-parsec-243510-a8f93bb5a906.json")
project = var.project_id
region = var.region
zone = var.zone
}
# Create random ID for VM suffix
resource "random_id" "vm_suffix" {
byte_length = 2
}
resource "google_compute_disk" "dataRim" {
provider = google-beta
name = "rim-datadisk-${random_id.vm_suffix.hex}"
type = var.disk_type
zone = var.zone
# labels = {
# environment = "dev"
# }
size = 50
}
resource "google_compute_instance" "rim" {
provider = google-beta
name = "rim-${random_id.vm_suffix.hex}"
machine_type = var.vm_type
# min_cpu_platform commented out during testing - e2 instances do not support
# min_cpu_platform = var.min_cpu
zone = var.zone
# hostname = "central-${random_id.vm_suffix.hex}"
# tags = ["foo", "bar"]
# timeouts {
# create = "60m"
# delete = "2h"
# }
boot_disk {
initialize_params {
image = var.image
}
}
attached_disk {
source = google_compute_disk.dataRim.name
}
# lifecycle {
# ignore_changes = [attached_disk]
# }
network_interface {
network = "default"
access_config {
network_tier = "STANDARD"
}
}
metadata = {
windows-startup-script-url = "gs://qliksense/scripts/bootstrap-rim.ps1"
}
service_account {
email = "terraform@esoteric-parsec-243510.iam.gserviceaccount.com"
scopes = ["userinfo-email", "compute-ro", "storage-rw"]
}
}
# data "google_compute_instance_serial_port" "serial" {
# provider = google-beta
# instance = google_compute_instance.central.name
# zone = var.zone
# port = 4
# }
# resource "local_file" "log" {
# filename = "${path.module}/tf-deploy.log"
# content = join("\n", "${data.google_compute_instance_serial_port.serial.contents}")
# }
# resource "null_resource" "bootstrap" {
# connection {
# type = "winrm"
# https = true
# insecure = true
# use_ntlm = true
# user = var.user_name
# password = var.user_password
# host = google_compute_instance.central.name
# timeout = "20m"
# }
# provisioner "remote-exec" {
# inline = [
# "powershell.exe -ExecutionPolicy Bypass -File E:\\deploy\\scripts\\win-nfs_client-install.ps1"
# ]
# }
# }

View File

@@ -0,0 +1,21 @@
# Configure return values from google_sql_database_instance
# output "psql_ip_address" {
# value = google_sql_database_instance.qseow-psql.private_ip_address
# }
output "gce_name" {
value = google_compute_instance.rim.name
}
output "gce_external_ip" {
value = google_compute_instance.rim.network_interface[0].access_config[0].nat_ip
}
output "gce_internal_ip" {
value = google_compute_instance.rim.network_interface[0].network_ip
}
# output "serial_out" {
# value = data.google_compute_instance_serial_port.serial.contents
# }

View File

@@ -0,0 +1,14 @@
{
"project_id": "esoteric-parsec-243510",
"region": "europe-west1",
"zone": "europe-west1-d",
"private_network": "projects/esoteric-parsec-243510/global/networks/default",
"database_version": "POSTGRES_9_6",
"vm_type": "e2-highmem-4",
"min_cpu": "Intel Skylake",
"image": "gce-uefi-images/windows-2019",
"disk_type": "pd-ssd",
"availability_type": "REGIONAL",
"user_name": "qlikadmin",
"user_password": "Qlik1234!"
}

View File

@@ -0,0 +1,116 @@
variable "project_id" {
type = string
description = "The project ID to manage the Cloud SQL resources"
}
variable "database_version" {
description = "The database version to use"
type = string
}
variable "region" {
type = string
description = "GCP Region"
default = "us-central1"
}
variable "tier" {
description = "The tier for the master instance."
type = string
default = "db-f1-micro"
}
variable "zone" {
type = string
description = "Zone target"
}
variable "disk_type" {
description = "GCE Boot/Attached Disk Type"
type = string
default = "pd-ssd"
}
variable "min_cpu" {
description = "GCE Minimum CPU Family"
type = string
default = "AMD Rome "
}
variable "image" {
description = "Path to GCE Image Type"
type = string
default = "windows-2019/windows-server-2019-dc-v20200908"
}
variable "vm_type" {
description = "The GCE machine type"
type = string
default = "n2d-highmem-8"
}
variable "availability_type" {
description = "The availability type for the master instance.This is only used to set up high availability for the PostgreSQL instance. Can be either `ZONAL` or `REGIONAL`."
type = string
default = "REGIONAL"
}
variable "backup_configuration" {
description = "The backup_configuration settings subblock for the database setings"
type = object({
enabled = bool
start_time = string
location = string
})
default = {
enabled = false
start_time = null
location = null
}
}
# variable "authorized_networks_a" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "71.164.77.198/32"
# }
# variable "authorized_networks_b" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
# variable "authorized_networks_c" {
# description = "CIDR Block to add to network ACL"
# type = string
# default = "127.0.0.1/32"
# }
variable "private_network" {
description = "Full path to private network ID"
type = string
default = "projects/esoteric-parsec-243510/global/networks/private-network"
}
variable "user_name" {
description = "The name of the default user"
type = string
default = "default"
}
variable "user_password" {
description = "The password for the default user. If not set, a random one will be generated and available in the generated_user_password output variable."
type = string
default = ""
}
variable "additional_users" {
description = "A list of users to be created in your cluster"
type = list(object({
name = string
password = string
}))
default = []
}

View File

@@ -0,0 +1,112 @@
#!/usr/bin/env pwsh
#
## Intended to be executed in a GitOps pipeline on the new GCE resource by remote-exec in TF
## or as a startup script via Metadata key windows-startup-script-url
##
if ($env:computername -notlike "central-*") {
exit 0
}
# Format and mount data disk
Write-Host "## ========================>> Create Data drive & dirs"
Get-Disk |
Where-Object partitionstyle -eq 'raw' |
Initialize-Disk -PartitionStyle GPT -PassThru |
New-Partition -DriveLetter E -UseMaximumSize |
Format-Volume -FileSystem NTFS -NewFileSystemLabel 'Data' -Confirm:$false
if (! (Test-Path E:\)) {
Write-Error "Drive not found"
exit 1
}
$deploy_path = "E:\deploy"
if (! (Test-Path $deploy_path)) {
New-Item -ItemType Directory -Path $deploy_path
New-Item -ItemType Directory -Path $deploy_path\binaries
New-Item -ItemType Directory -Path $deploy_path\modules
New-Item -ItemType Directory -Path $deploy_path\modules\tf
New-Item -ItemType Directory -Path $deploy_path\modules\ps
}
Write-Host "## ========================>> Create Local Accounts and add to Administrators Group"
if(!(Get-LocalUser -Name qservice -ErrorAction Ignore)) {
$password = ConvertTo-SecureString -String 'Qlik1234!' -AsPlainText -Force
New-LocalUser `
-Name 'qservice' `
-Password $password `
-PasswordNeverExpires `
-UserMayNotChangePassword
}
if(!(Get-LocalUser -Name qlikadmin -ErrorAction Ignore)) {
$password = ConvertTo-SecureString -String 'Qlik1234!' -AsPlainText -Force
New-LocalUser `
-Name 'qlikadmin' `
-Password $password `
-PasswordNeverExpires `
-UserMayNotChangePassword
}
Add-LocalGroupMember -Group "Administrators" -Member "qservice", "qlikadmin"
Write-Host "## ========================>> Copy scripts and binaries from Cloud Storage Bucket"
gsutil -m cp -r gs://qliksense/scripts $deploy_path\
gsutil -m cp gs://qliksense/binaries/Qlik_Sense* $deploy_path\binaries\
gsutil -m cp gs://qliksense/binaries/vscode_stable.exe $deploy_path\binaries\
gsutil -m cp gs://qliksense/binaries/firefox_latest.exe $deploy_path\binaries\
gsutil -m cp gs://qliksense/binaries/ps7.zip $deploy_path\binaries\
# gsutil -m cp -r gs://qliksense/modules 'C:\Program Files\WindowsPowerShell\Modules'
# Invoke-WebRequest -Uri https://github.com/PowerShell/PowerShell/releases/download/v7.0.3/PowerShell-7.0.3-win-x64.zip -OutFile $deploy_path\binaries\ps7.zip
# Invoke-WebRequest -Uri https://aka.ms/win32-x64-user-stable -Outfile $deploy_path\binaries\vscode_stable.exe
# Invoke-WebRequest -Uri "https://download.mozilla.org/?product=firefox-latest-ssl&os=win64&lang=en-US" -Outfile $deploy_path\binaries\firefox_latest.exe
Unblock-File -Path $deploy_path\binaries\*
Unblock-File -Path $deploy_path\scripts\*
# WinRM Connects
New-Item -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation -Name AllowFreshCredentialsWhenNTLMOnly -Force
New-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation\AllowFreshCredentialsWhenNTLMOnly -Name 1 -Value * -PropertyType String
Write-Host "## ========================>> Import PS Modules"
Get-PackageProvider -Name NuGet -ForceBootstrap
Install-Module PSDscResources -Force
Install-Module QlikResources -Force
Write-Host "## ========================>> Deploy PS7 | Firefox | VS Code"
Expand-Archive -Path $deploy_path\binaries\ps7.zip -DestinationPath $deploy_path\binaries\ps7
Invoke-Command -ScriptBlock {Start-Process -FilePath "$deploy_path\binaries\vscode_stable.exe" -ArgumentList "/VERYSILENT /MERGETASKS=!runcode" -Wait -PassThru} | Out-Null
Invoke-Command -ScriptBlock {Start-Process -FilePath "$deploy_path\binaries\firefox_latest.exe" -ArgumentList "/s" -Wait -PassThru} | Out-Null
# QSEoW FW Rule
Write-Host "## ========================>> Create QSEoW FW Rule"
New-NetFirewallRule -DisplayName "Qlik Sense" -Direction Inbound -LocalPort 443, 4244,4242, 4432, 4444, 5355, 5353, 80, 4248, 3090, 4000, 5555, 5556, 4993, 4994 -Protocol TCP -Action Allow -ea Stop | Out-Null
# Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False
#### Enable NFS Client, set Anon user to UID:GID 0 == root. Restart service.
Write-Host "## ========================>> Installing NFS Client"
Install-WindowsFeature -Name NFS-Client
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default" `
-Name "AnonymousUid" -Value "0" -PropertyType DWORD
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default" `
-Name "AnonymousGid" -Value "0" -PropertyType DWORD
nfsadmin client stop
nfsadmin client start
#### Launch silent install
Write-Host "========================>> Installing QSEoW"
Invoke-Command -ScriptBlock {Start-Process -FilePath "E:\deploy\binaries\Qlik_Sense_setup.exe" -ArgumentList "-s -log E:\deploy\deploy.log accepteula=1 installdir=E:\deploy\Qlik dbpassword=Qlik1234! hostname=$($env:computername) userwithdomain=$($env:computername)\qservice password=Qlik1234! bundleinstall=dashboard,visualization spc=E:\deploy\scripts\cen.xml" -Wait -PassThru} #| Out-Null
# HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
# New-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce' -Name 'Run' -Value '<insert_script_command_here>'
Set-GceInstance -Name ($env:computername).ToLower() -Zone europe-west1-d -AddTag "bootstrapped"
Set-GceInstance -Name ($env:computername).ToLower() -Zone europe-west1-d -RemoveMetadata "windows-startup-script-url"
Exit 0

View File

@@ -0,0 +1,112 @@
#!/usr/bin/env pwsh
#
## Intended to be executed in a GitOps pipeline on the new GCE resource by remote-exec in TF
## or as a startup script via Metadata key windows-startup-script-url
##
if ($env:computername -notlike "rim-*") {
exit 0
}
# Format and mount data disk
Write-Host "## ========================>> Create Data drive & dirs"
Get-Disk |
Where-Object partitionstyle -eq 'raw' |
Initialize-Disk -PartitionStyle GPT -PassThru |
New-Partition -DriveLetter E -UseMaximumSize |
Format-Volume -FileSystem NTFS -NewFileSystemLabel 'Data' -Confirm:$false
if (! (Test-Path E:\)) {
Write-Error "Drive not found"
exit 1
}
$deploy_path = "E:\deploy"
if (! (Test-Path $deploy_path)) {
New-Item -ItemType Directory -Path $deploy_path
New-Item -ItemType Directory -Path $deploy_path\binaries
New-Item -ItemType Directory -Path $deploy_path\modules
New-Item -ItemType Directory -Path $deploy_path\modules\tf
New-Item -ItemType Directory -Path $deploy_path\modules\ps
}
Write-Host "## ========================>> Create Local Accounts and add to Administrators Group"
if(!(Get-LocalUser -Name qservice -ErrorAction Ignore)) {
$password = ConvertTo-SecureString -String 'Qlik1234!' -AsPlainText -Force
New-LocalUser `
-Name 'qservice' `
-Password $password `
-PasswordNeverExpires `
-UserMayNotChangePassword
}
if(!(Get-LocalUser -Name qlikadmin -ErrorAction Ignore)) {
$password = ConvertTo-SecureString -String 'Qlik1234!' -AsPlainText -Force
New-LocalUser `
-Name 'qlikadmin' `
-Password $password `
-PasswordNeverExpires `
-UserMayNotChangePassword
}
Add-LocalGroupMember -Group "Administrators" -Member "qservice", "qlikadmin"
Write-Host "## ========================>> Copy scripts and binaries from Cloud Storage Bucket"
gsutil -m cp -r gs://qliksense/scripts $deploy_path\
gsutil -m cp gs://qliksense/binaries/Qlik_Sense* $deploy_path\binaries\
gsutil -m cp gs://qliksense/binaries/vscode_stable.exe $deploy_path\binaries\
gsutil -m cp gs://qliksense/binaries/firefox_latest.exe $deploy_path\binaries\
gsutil -m cp gs://qliksense/binaries/ps7.zip $deploy_path\binaries\
# gsutil -m cp -r gs://qliksense/modules 'C:\Program Files\WindowsPowerShell\Modules'
# Invoke-WebRequest -Uri https://github.com/PowerShell/PowerShell/releases/download/v7.0.3/PowerShell-7.0.3-win-x64.zip -OutFile $deploy_path\binaries\ps7.zip
# Invoke-WebRequest -Uri https://aka.ms/win32-x64-user-stable -Outfile $deploy_path\binaries\vscode_stable.exe
# Invoke-WebRequest -Uri "https://download.mozilla.org/?product=firefox-latest-ssl&os=win64&lang=en-US" -Outfile $deploy_path\binaries\firefox_latest.exe
Unblock-File -Path $deploy_path\binaries\*
Unblock-File -Path $deploy_path\scripts\*
# WinRM Connects
New-Item -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation -Name AllowFreshCredentialsWhenNTLMOnly -Force
New-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation\AllowFreshCredentialsWhenNTLMOnly -Name 1 -Value * -PropertyType String
Write-Host "## ========================>> Import PS Modules"
Get-PackageProvider -Name NuGet -ForceBootstrap
Install-Module PSDscResources -Force
Install-Module QlikResources -Force
Write-Host "## ========================>> Deploy PS7 | Firefox | VS Code"
Expand-Archive -Path $deploy_path\binaries\ps7.zip -DestinationPath $deploy_path\binaries\ps7
Invoke-Command -ScriptBlock {Start-Process -FilePath "$deploy_path\binaries\vscode_stable.exe" -ArgumentList "/VERYSILENT /MERGETASKS=!runcode" -Wait -PassThru} | Out-Null
Invoke-Command -ScriptBlock {Start-Process -FilePath "$deploy_path\binaries\firefox_latest.exe" -ArgumentList "/s" -Wait -PassThru} | Out-Null
# QSEoW FW Rule
Write-Host "## ========================>> Create QSEoW FW Rule"
New-NetFirewallRule -DisplayName "Qlik Sense" -Direction Inbound -LocalPort 443, 4244,4242, 4432, 4444, 5355, 5353, 80, 4248, 3090, 4000, 5555, 5556, 4993, 4994 -Protocol TCP -Action Allow -ea Stop | Out-Null
# Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False
#### Enable NFS Client, set Anon user to UID:GID 0 == root. Restart service.
Write-Host "## ========================>> Installing NFS Client"
Install-WindowsFeature -Name NFS-Client
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default" `
-Name "AnonymousUid" -Value "0" -PropertyType DWORD
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default" `
-Name "AnonymousGid" -Value "0" -PropertyType DWORD
nfsadmin client stop
nfsadmin client start
#### Launch silent install
Write-Host "========================>> Installing QSEoW"
Invoke-Command -ScriptBlock {Start-Process -FilePath "E:\deploy\binaries\Qlik_Sense_setup.exe" -ArgumentList "-s -log E:\deploy\deploy.log accepteula=1 installdir=E:\deploy\Qlik dbpassword=Qlik1234! hostname=$($env:computername) userwithdomain=$($env:computername)\qservice password=Qlik1234! bundleinstall=dashboard,visualization spc=E:\deploy\scripts\rim.xml" -Wait -PassThru} #| Out-Null
# HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
# New-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce' -Name 'Run' -Value '<insert_script_command_here>'
Set-GceInstance -Name $shortname -Zone europe-west1-d -AddTag "bootstrapped"
Set-GceInstance -Name $shortname -Zone europe-west1-d -RemoveMetadata "windows-startup-script-url"
Exit 0

View File

@@ -0,0 +1,79 @@
#!/usr/bin/env pwsh
#
## Intended to be executed in a GitOps pipeline on the new GCE resource by remote-exec in TF
##
Enable-PSRemoting
winrm set 'winrm/config/client' '@{TrustedHosts="*"}'
if(!(Get-LocalUser -Name qservice -ErrorAction Ignore)) {
$password = ConvertTo-SecureString -String 'Qlik1234!' -AsPlainText -Force
New-LocalUser `
-Name 'qservice' `
-Password $password `
-PasswordNeverExpires `
-UserMayNotChangePassword
}
Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False
New-Item -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation -Name AllowFreshCredentialsWhenNTLMOnly -Force
New-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation\AllowFreshCredentialsWhenNTLMOnly -Name 1 -Value * -PropertyType String
# if ($env:computername -ne 'central') {
# exit 0
# }
# Get-WmiObject -Class Win32_Volume -Filter "DriveType=5" | Set-WmiInstance -Arguments @{DriveLetter="Z:"}
Get-Disk |
Where-Object partitionstyle -eq 'raw' |
Initialize-Disk -PartitionStyle GPT -PassThru |
New-Partition -DriveLetter E -UseMaximumSize |
Format-Volume -FileSystem NTFS -NewFileSystemLabel 'Data' -Confirm:$false
if (! (Test-Path E:\)) {
Write-Error "Drive not found"
exit 1
}
$deploy_path = "E:\deploy"
if (-Not (Test-Path $deploy_path)) {
New-Item -ItemType Directory -Path $deploy_path
New-Item -ItemType Directory -Path $deploy_path\binaries
New-Item -ItemType Directory -Path $deploy_path\modules
New-Item -ItemType Directory -Path $deploy_path\modules\tf
New-Item -ItemType Directory -Path $deploy_path\modules\ps
}
# Update these gcloud commands to be vars, allows portability
#
# CLOUDCLI_UPDATE
# OBJCLI_COPY
# gcloud components update -Force
gsutil -m cp gs://qliksense/Qlik_Sense* $deploy_path\binaries\
gsutil -m cp -r gs://qliksense/scripts $deploy_path\
gsutil -m cp -r gs://qliksense/modules 'C:\Program Files\WindowsPowerShell\Modules'
# Push-Location $deploy_path\modules\ps
Get-PackageProvider -Name NuGet -ForceBootstrap
# Below will also download and save the QlikResources requirements modules
# Save-Module -Path $deploy_path/modules/ps/ -Name QlikResources -RequiredVersion 1.9.2
# Save-Module -Path $deploy_path/modules/ps/ -Name GoogleCloud
# HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
# New-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce' -Name 'Run' -Value '<insert_script_command_here>'
Set-ExecutionPolicy Bypass -Scope Process -Force; E:\deploy\scripts\win-nfs_client-install.ps1
gcloud compute instances add-tags central-12d5 --tags=bootstrapped --zone europe-west1-d
# Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
# choco install git --no-progress
# Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
# Update-SessionEnvironment
# git clone https://gitlab+deploy-token-52544:YH-1SVsTrNmzj7AXz7oh@gitlab.com/ahaydon/cityclarity-psm.git ./CitiClarity
# Pop-Location
Exit 0

View File

@@ -0,0 +1,24 @@
<?xml version="1.0"?>
<SharedPersistenceConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DbUserName>qliksenserepository</DbUserName>
<DbUserPassword>Qlik1234!</DbUserPassword>
<DbHost>10.54.242.14</DbHost>
<DbPort>5432</DbPort>
<RootDir>\\10.159.210.26\qlikshare</RootDir>
<StaticContentRootDir>\\10.159.210.26\qlikshare\StaticContent</StaticContentRootDir>
<ArchivedLogsDir>\\10.159.210.26\qlikshare\ArchivedLogs</ArchivedLogsDir>
<AppsDir>\\10.159.210.26\qlikshare\Apps</AppsDir>
<CreateCluster>true</CreateCluster>
<InstallLocalDb>false</InstallLocalDb>
<ConfigureDbListener>false</ConfigureDbListener>
<ListenAddresses>*</ListenAddresses>
<IpRange>0.0.0.0/0,::/0</IpRange>
<MaxConnections>100</MaxConnections>
<!-- <JoinCluster>true</JoinCluster> -->
<ConfigureLogging>true</ConfigureLogging>
<SetupLocalLoggingDb>false</SetupLocalLoggingDb>
<QLogsWriterPassword>Qlik1234!</QLogsWriterPassword>
<QLogsReaderPassword>Qlik1234!</QLogsReaderPassword>
<QLogsHostname>10.54.242.14</QLogsHostname>
<QLogsPort>5432</QLogsPort>
</SharedPersistenceConfiguration>

View File

@@ -0,0 +1,96 @@
$configData = @{
AllNodes = @(@{
NodeName = 'localhost'
PSDscAllowPlainTextPassword = $true
})
}
$password = ConvertTo-SecureString -String 'password' -AsPlainText -Force
$SenseService = New-Object System.Management.Automation.PSCredential("$env:computername\qservice", $password)
$QlikAdmin = New-Object System.Management.Automation.PSCredential("$env:computername\qlikadmin", $password)
Configuration QlikConfig
{
Import-DscResource -ModuleName QlikResources, PSDscResources
Node localhost
{
# User QlikAdmin
# {
# UserName = $QlikAdmin.GetNetworkCredential().UserName
# Password = $QlikAdmin
# FullName = 'Qlik User'
# PasswordChangeRequired = $false
# PasswordNeverExpires = $true
# Ensure = 'Present'
# DependsOn = "[Windows]local"
# }
# User SenseService
# {
# UserName = $SenseService.GetNetworkCredential().UserName
# Password = $SenseService
# FullName = 'Qlik Sense Service Account'
# PasswordChangeNotAllowed = $true
# PasswordChangeRequired = $false
# PasswordNeverExpires = $true
# Ensure = 'Present'
# DependsOn = "[Windows]local"
# }
# Group Administrators
# {
# GroupName = 'Administrators'
# MembersToInclude = $QlikAdmin.GetNetworkCredential().UserName, $SenseService.GetNetworkCredential().UserName
# DependsOn = "[User]QlikAdmin", "[User]SenseService"
# }
QlikCentral CentralNode
{
SenseService = $SenseService
QlikAdmin = $QlikAdmin
ProductName = 'Qlik Sense September 2020 Patch 2'
SetupPath = 'E:\deploy\binaries\Qlik_Sense_setup.exe'
PatchPath = 'E:\deploy\binaries\Qlik_Sense_update.exe'
ClusterShareHost = ""
License = @{
Serial = '1234567890'
Control = '12345'
Name = 'User'
Organization = 'Organization'
}
PSDscRunasCredential = $QlikAdmin
DependsOn = "[MSFT_GroupResource]Administrators"
}
# QlikVirtualProxy SAML
# {
# Prefix = "saml"
# Description = "SAML"
# SessionCookieHeaderName = "X-Qlik-Session-SAML"
# LoadBalancingServerNodes = "name eq 'Central'"
# AuthenticationMethod = "saml"
# SamlMetadataIdp = (Get-Content -raw E:\deploy\idp-metadata.xml)
# SamlHostUri = "https://$($env:computername)"
# SamlEntityId = "https://$($env:computername)/saml"
# SamlAttributeUserId = "uid"
# SamlAttributeUserDirectory = "[SAML]"
# SamlAttributeMapMandatory = @{
# mail = 'email'
# }
# samlSlo = $true
# SamlMetadataExportPath = "E:\deploy\saml_metadata_sp.xml"
# Proxy = $env:computername
# PSDscRunasCredential = $QlikAdmin
# Ensure = "Present"
# }
}
}
QlikConfig -ConfigurationData $configData
if (! (Test-Path E:\deploy\scripts\QlikConfig)) {
New-Item -ItemType Directory -Path E:\deploy\scripts\QlikConfig
}
Start-DscConfiguration -Path E:\deploy\scripts\QlikConfig -Wait -Verbose -Force

View File

@@ -0,0 +1,109 @@
#!/usr/bin/env pwsh
#
## Intended to be executed in a GitOps pipeline on the new GCE resource by remote-exec in TF
## or as a startup script via Metadata key windows-startup-script-url
##
if ($env:computername -notlike "central-*") {
exit 0
}
#### Format and mount data disk
Write-Host "<---- Create Data drive & dirs"
Get-Disk |
Where-Object partitionstyle -eq 'raw' |
Initialize-Disk -PartitionStyle GPT -PassThru |
New-Partition -DriveLetter E -UseMaximumSize |
Format-Volume -FileSystem NTFS -NewFileSystemLabel 'Data' -Confirm:$false
if (! (Test-Path E:\)) {
Write-Error "Drive not found"
exit 1
}
$deploy_path = "E:\deploy"
if (! (Test-Path $deploy_path)) {
New-Item -ItemType Directory -Path $deploy_path
New-Item -ItemType Directory -Path $deploy_path\binaries
New-Item -ItemType Directory -Path $deploy_path\modules
New-Item -ItemType Directory -Path $deploy_path\modules\tf
New-Item -ItemType Directory -Path $deploy_path\modules\ps
}
Write-Host "<---- Copy scripts and binaries from Cloud Storage Bucket"
gcloud components update -Force
gsutil -m cp -r gs://qliksense/scripts $deploy_path\
gsutil -m cp gs://qliksense/binaries/Qlik_Sense* $deploy_path\binaries\
# gsutil -m cp -r gs://qliksense/modules 'C:\Program Files\WindowsPowerShell\Modules'
Invoke-WebRequest -Uri https://github.com/PowerShell/PowerShell/releases/download/v7.0.3/PowerShell-7.0.3-win-x64.zip -OutFile $deploy_path\binaries\ps7.zip
Invoke-WebRequest -Uri https://aka.ms/win32-x64-user-stable -Outfile $deploy_path\binaries\vscode_stable.exe
Invoke-WebRequest -Uri "https://download.mozilla.org/?product=firefox-latest-ssl&os=win64&lang=en-US" -Outfile $deploy_path\binaries\firefox_latest.exe
Unblock-File -Path $deploy_path\binaries\*
Unblock-File -Path $deploy_path\scripts\*
Write-Host "<---- Create Local Accounts and add to Administrators Group"
if(!(Get-LocalUser -Name qservice -ErrorAction Ignore)) {
$password = ConvertTo-SecureString -String 'Qlik1234!' -AsPlainText -Force
New-LocalUser `
-Name 'qservice' `
-Password $password `
-PasswordNeverExpires `
-UserMayNotChangePassword
}
if(!(Get-LocalUser -Name qlikadmin -ErrorAction Ignore)) {
$password = ConvertTo-SecureString -String 'Qlik1234!' -AsPlainText -Force
New-LocalUser `
-Name 'qlikadmin' `
-Password $password `
-PasswordNeverExpires `
-UserMayNotChangePassword
}
Add-LocalGroupMember -Group "Administrators" -Member "qservice", "qlikadmin"
#### WinRM Connects
New-Item -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation -Name AllowFreshCredentialsWhenNTLMOnly -Force
New-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation\AllowFreshCredentialsWhenNTLMOnly -Name 1 -Value * -PropertyType String
Write-Host "<---- Import PS Modules and Install Firefox / VS Code"
Get-PackageProvider -Name NuGet -ForceBootstrap
Install-Module PSDesiredStateConfiguration -Force
Install-Module PSDscResources -Force
Install-Module QlikResources -Force
Expand-Archive -Path $deploy_path\binaries\ps7.zip -DestinationPath $deploy_path\binaries\ps7
& $deploy_path\binaries\vscode_stable.exe /VERYSILENT /MERGETASKS=!runcode
& $deploy_path\binaries\firefox_latest.exe /s
# HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
# New-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce' -Name 'Run' -Value '<insert_script_command_here>'
#### QSEoW FW Rule
Write-Host "<---- Create QSEoW FW Rule"
New-NetFirewallRule -DisplayName "Qlik Sense" -Direction Inbound -LocalPort 443, 4244,4242, 4432, 4444, 5355, 5353, 80, 4248, 3090, 4000, 5555, 5556, 4993, 4994 -Protocol TCP -Action Allow -ea Stop | Out-Null
# Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False
#### Enable NFS Client, set Anon user to UID:GID 0 == root. Restart service.
Write-Host -Message "<---- Installing NFS Client"
Install-WindowsFeature -Name NFS-Client
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default" `
-Name "AnonymousUid" -Value "0" -PropertyType DWORD
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default" `
-Name "AnonymousGid" -Value "0" -PropertyType DWORD
nfsadmin client stop
nfsadmin client start
#### Launch silent install
# Write-Host "<---- Installing QSEoW"
# Invoke-Command -ScriptBlock {Start-Process -FilePath "E:\deploy\binaries\Qlik_Sense_setup.exe" -ArgumentList "-s -log E:\deploy\deploy.log accepteula=1 installdir=E:\deploy\Qlik dbpassword=Qlik1234! hostname=$($env:computername) userwithdomain=$($env:computername)\qservice password=Qlik1234! bundleinstall=dashboard,visualization spc=E:\deploy\scripts\spc.xml" -Wait -PassThru} | Out-Null
Set-GceInstance -Name $shortname -Zone europe-west1-d -AddTag "bootstrapped"
Set-GceInstance -Name $shortname -Zone europe-west1-d -RemoveMetadata "windows-startup-script-url"
Exit 0

View File

@@ -0,0 +1,24 @@
<?xml version="1.0"?>
<SharedPersistenceConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DbUserName>qliksenserepository</DbUserName>
<DbUserPassword>Qlik1234!</DbUserPassword>
<DbHost>10.54.242.14</DbHost>
<DbPort>5432</DbPort>
<RootDir>\\10.159.210.26\qlikshare</RootDir>
<StaticContentRootDir>\\10.159.210.26\qlikshare\StaticContent</StaticContentRootDir>
<ArchivedLogsDir>\\10.159.210.26\qlikshare\ArchivedLogs</ArchivedLogsDir>
<AppsDir>\\10.159.210.26\qlikshare\Apps</AppsDir>
<CreateCluster>false</CreateCluster>
<InstallLocalDb>false</InstallLocalDb>
<ConfigureDbListener>false</ConfigureDbListener>
<ListenAddresses>*</ListenAddresses>
<IpRange>0.0.0.0/0,::/0</IpRange>
<MaxConnections>100</MaxConnections>
<!-- <JoinCluster>true</JoinCluster> -->
<ConfigureLogging>true</ConfigureLogging>
<SetupLocalLoggingDb>false</SetupLocalLoggingDb>
<QLogsWriterPassword>Qlik1234!</QLogsWriterPassword>
<QLogsReaderPassword>Qlik1234!</QLogsReaderPassword>
<QLogsHostname>10.54.242.14</QLogsHostname>
<QLogsPort>5432</QLogsPort>
</SharedPersistenceConfiguration>

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env pwsh
# Install NFS Client on Windows via PS
#
# Wait for bootstrap.ps1 to finish before proceeding.
# $bootScript = "bootstrap.ps1"
# Wait-Process -Name $bootScript -ErrorAction SilentlyContinue -Timeout 1200
# Enable NFS Client, set Anon user to UID:GID 0 == root. Restart service.
Write-Host -Message "<---- Installing NFS Client"
Install-WindowsFeature -Name NFS-Client
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default" `
-Name "AnonymousUid" -Value "0" -PropertyType DWORD
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default" `
-Name "AnonymousGid" -Value "0" -PropertyType DWORD
nfsadmin client stop
nfsadmin client start
# & E:\deploy\binaries\Qlik_Sense_setup.exe -s -l E:\deploy\deploy.log spc="E:\deploy\scripts\spc.xml" installdir="E:\deploy\Qlik" userwithdomain="central-b445\qservice" userpassword="Qlik1234!" dbpassword="Qlik1234!" accepteula=1 skipvalidation=1 bundleinstall=1 skipdbconfig=1
Write-Host "<---- Installing QSEoW"
Invoke-Command -ScriptBlock {Start-Process -FilePath "E:\deploy\binaries\Qlik_Sense_setup.exe" -ArgumentList "-s -log E:\deploy\deploy.log accepteula=1 installdir=E:\deploy\Qlik dbpassword=Qlik1234! hostname=$($env:computername) userwithdomain=$($env:computername)\qservice password=Qlik1234! bundleinstall=dashboard,visualization spc=E:\deploy\scripts\spc.xml" -Wait -PassThru} | Out-Null