Skip to content

Commit 349e308

Browse files
authored
Add OCI basic setup that will be used for the OCI Guide (#21)
* Add exercise for a Basic OCI setup. * Update readme file. * Resolve shellcheck issues * Update all Readmes and improve deploy.sh to organize deployed application * Additional update to the Readme * More updates to readme and improvements to utility scripts * Additional updates to readme * Change update_config_values.sh to allow config values to be replaced again with newer values. * Minor correction in the readme.
1 parent e1ee0b7 commit 349e308

26 files changed

+1316
-0
lines changed

hols/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
* [Grafana Dashboard for Helidon](grafana/README.md)
44
* [LangChain4J Integration](langchain4j/README.md)
55
* [Using OCI Devops to deploy a Helidon application to OKE or a Compute Instance](oci-devops/README.md)
6+
* [Deploying a Helidon OCI MP Application on a Basic OCI Setup](oci-basic-setup/README.md)

hols/oci-basic-setup/README.md

Lines changed: 276 additions & 0 deletions
Large diffs are not rendered by default.

hols/oci-basic-setup/deploy.sh

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
#!/bin/bash
2+
#
3+
# Copyright (c) 2025 Oracle and/or its affiliates.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
# Use this to specify the JDK Installer version in tar_gz format
19+
JDK_TAR_GZ_INSTALLER="https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.tar.gz"
20+
21+
HELIDON_MP_APP_ZIP=oci-mp-server.zip
22+
DEFAULT_PROJECT_PATH=~/oci-mp
23+
SCRIPT_DIR=$(dirname "$0")
24+
# shellcheck disable=SC1091
25+
source "${SCRIPT_DIR}"/get_common.sh
26+
27+
# Main routine
28+
if [ -z "${1}" ]; then
29+
read -r -p "Enter the Helidon MP project's root directory (default: ${DEFAULT_PROJECT_PATH}): " PROJECT_PATH
30+
# Use eval to expand ~ if it is part of the input
31+
PROJECT_PATH=$(eval echo -n "${PROJECT_PATH:-${DEFAULT_PROJECT_PATH}}")
32+
echo "$PROJECT_PATH"
33+
else
34+
PROJECT_PATH=${1}
35+
fi
36+
if [ ! -d "${PROJECT_PATH}" ]; then
37+
echo "Error: \"${PROJECT_PATH}\" is not a valid directory"
38+
exit 1
39+
fi
40+
CURRENT_DIR=$(pwd)
41+
SERVER_BIN_DIR="${PROJECT_PATH}/server/target"
42+
cd "${SERVER_BIN_DIR}" || exit 1
43+
44+
# Assemble the application zip
45+
zip -r "${CURRENT_DIR}/${HELIDON_MP_APP_ZIP}" libs oci-mp-server.jar
46+
cd "${CURRENT_DIR}" || exit 1
47+
48+
# Generate private key file that will be use to ssh or scp to the instance
49+
"${SCRIPT_DIR}"/get.sh create_ssh_private_key
50+
# Get instance public IP
51+
PUBLIC_IP=$("${SCRIPT_DIR}"/get.sh public_ip)
52+
# Upload the application zip
53+
scp -o StrictHostKeyChecking=accept-new -i private.key oci-mp-server.zip opc@"${PUBLIC_IP}":/home/opc
54+
55+
# Download & install jdk and run app
56+
ssh -i private.key opc@"${PUBLIC_IP}" "bash -s ${HELIDON_MP_APP_ZIP} ${JDK_TAR_GZ_INSTALLER}" << 'EOF'
57+
HELIDON_MP_APP_ZIP=${1}
58+
JDK_TAR_GZ_INSTALLER=${2}
59+
60+
# Create application and log directory
61+
export APP_DIR=~/oci-mp/app
62+
export LOG_DIR=~/oci-mp/log
63+
mkdir -p "${APP_DIR}"
64+
mkdir -p "${LOG_DIR}"
65+
66+
# Unzip the application binary
67+
unzip -o "${HELIDON_MP_APP_ZIP}" -d "${APP_DIR}"
68+
rm "${HELIDON_MP_APP_ZIP}"
69+
70+
# Download and extract JDK
71+
JDK_TAR_GZ_INSTALLER_BASE=$(basename ${JDK_TAR_GZ_INSTALLER})
72+
if ! ls "${JDK_TAR_GZ_INSTALLER_BASE}" ; then
73+
rm -f "*jdk*.tar.gz"
74+
rm -rf jdk*
75+
# Download JDK
76+
curl -O "${JDK_TAR_GZ_INSTALLER}" && echo "JDK downloaded successfully"
77+
tar xzf ${JDK_TAR_GZ_INSTALLER_BASE} && echo "JDK installed successfully"
78+
fi
79+
80+
# Create Service file
81+
export JAVA_BIN=$(ls -d "$(pwd)"/jdk*/)bin
82+
cat << EOF_INNER > helidon-app.service.new
83+
[Unit]
84+
Description=Helidon OCI-MP application service
85+
After=syslog.target network.target
86+
87+
[Service]
88+
User=opc
89+
Type=simple
90+
WorkingDirectory=/home/opc
91+
ExecStart=/bin/bash -c '${JAVA_BIN}/java -jar ${APP_DIR}/oci-mp-server.jar &> ${LOG_DIR}/oci-mp-server.log'
92+
93+
[Install]
94+
WantedBy=multi-user.target
95+
EOF_INNER
96+
97+
# Set appropriate SELinux Context for helidon-app.service if SELinux is in enforcing mode
98+
SELINUX_ENFORCE_STATUS=$(getenforce)
99+
if [ "${SELINUX_ENFORCE_STATUS}" == "Enforcing" ]; then
100+
echo "Setting context for systemd service file"
101+
chcon system_u:object_r:systemd_unit_file_t:s0 helidon-app.service.new
102+
fi
103+
104+
# These next steps will set and start the application up as a systemd service that will automatically be restarted
105+
# whenever the instance restarts.
106+
if ! systemctl is-enabled helidon-app.service; then
107+
echo "Enabling helidon-app.service"
108+
mv -f helidon-app.service.new helidon-app.service
109+
sudo systemctl enable /home/opc/helidon-app.service
110+
else
111+
# reload systemd manager configuration as helidon-app.service has changed
112+
if ! diff helidon-app.service helidon-app.service.new; then
113+
echo "Reloading systemd manager configuration"
114+
mv -f helidon-app.service.new helidon-app.service
115+
sudo systemctl daemon-reload
116+
# ignore the new helidon-app.service as it has not changed
117+
else
118+
rm -f helidon-app.service.new
119+
fi
120+
fi
121+
echo "Starting helidon-app.service"
122+
sudo systemctl restart helidon-app.service
123+
124+
# Check if Helidon is ready in 60 seconds using the readiness healthcheck endpoint of the app.
125+
TIMEOUT_SEC=60
126+
start_time="$(date -u +%s)"
127+
while true; do
128+
curl -s http://localhost:8080/health/ready | grep -q '"status":"UP"'
129+
if [ $? -eq 0 ]; then
130+
echo "Helidon app is now running with pid $(ps -fe | grep oci-mp-server | grep -v -e bash -e grep | awk '{print $2}')"
131+
break
132+
fi
133+
current_time="$(date -u +%s)"
134+
elapsed_seconds=$(($current_time-$start_time))
135+
if [ $elapsed_seconds -gt $TIMEOUT_SEC ]; then
136+
echo "Error: Helidon app failed to run successfully. Printing the logs..."
137+
cat oci-mp-server.log
138+
exit 1
139+
fi
140+
sleep 1
141+
done
142+
EOF
143+
144+
# delete private.key and application zip
145+
rm -f private.key
146+
rm -f "${HELIDON_MP_APP_ZIP}"

hols/oci-basic-setup/get.sh

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#!/bin/bash
2+
#
3+
# Copyright (c) 2025 Oracle and/or its affiliates.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
SCRIPT_DIR=$(dirname "$0")
19+
export TERRAFORM_TFSTATE=${SCRIPT_DIR}/terraform.tfstate
20+
# shellcheck disable=SC1091
21+
source "${SCRIPT_DIR}"/get_common.sh
22+
23+
# Command Choices:
24+
COMPARTMENT_ID_COMMAND=compartment_id
25+
COMPARTMENT_NAME_COMMAND=compartment_name
26+
CUSTOM_LOG_ID_COMMAND=custom_log_id
27+
PUBLIC_IP_COMMAND=public_ip
28+
ALL_COMMAND=all
29+
CREATE_SSH_PRIVATE_KEY_COMMAND=create_ssh_private_key
30+
31+
get_compartment_id() {
32+
get_resource_value compartment_id
33+
echo
34+
}
35+
36+
get_compartment_name() {
37+
get_resource_value compartment_name
38+
echo
39+
}
40+
41+
get_custom_log_id() {
42+
get_resource_value application_log_id
43+
echo
44+
}
45+
46+
get_public_ip() {
47+
get_resource_value instance_public_ip
48+
echo
49+
}
50+
51+
# Extract ssh private key value from output, save in private.key and change file mode to read-only
52+
create_ssh_private_key() {
53+
rm -rf private.key
54+
local private_key
55+
private_key=$(jq -r '.outputs.instance_ssh_private_key.value' "${TERRAFORM_TFSTATE}")
56+
if [[ -n "${private_key}" && "${private_key}" != "null" ]]; then
57+
echo -n "${private_key}" > private.key
58+
chmod go-rw private.key
59+
echo -n "Created private.key and can be used to ssh to the deployment instance by running this command: \"ssh -i private.key opc@"
60+
get_resource_value instance_public_ip
61+
echo "\""
62+
else
63+
echo "Private key does not exist"
64+
fi
65+
}
66+
67+
# Display usage information for this tool.
68+
display_help()
69+
{
70+
local left_justified_size=24
71+
echo "Usage: $(basename "$0") {${COMPARTMENT_ID_COMMAND}|{${COMPARTMENT_NAME_COMMAND}|${CUSTOM_LOG_ID_COMMAND}|${PUBLIC_IP_COMMAND}|${ALL_COMMAND}|${CREATE_SSH_PRIVATE_KEY_COMMAND}}"
72+
echo
73+
print_command_detail ${COMPARTMENT_ID_COMMAND} "displays compartment id" ${left_justified_size}
74+
print_command_detail ${COMPARTMENT_NAME_COMMAND} "displays compartment name" ${left_justified_size}
75+
print_command_detail ${CUSTOM_LOG_ID_COMMAND} "displays application custom log id" ${left_justified_size}
76+
print_command_detail ${PUBLIC_IP_COMMAND} "displays the public ip of the compute host instance used for deployment" ${left_justified_size}
77+
print_command_detail ${ALL_COMMAND} "displays ${COMPARTMENT_ID_COMMAND}, ${CUSTOM_LOG_ID_COMMAND}, ${PUBLIC_IP_COMMAND}" ${left_justified_size}
78+
echo " ---"
79+
print_command_detail ${CREATE_SSH_PRIVATE_KEY_COMMAND} "creates private.key that can be used to ssh to the compute instance" ${left_justified_size}
80+
echo
81+
}
82+
83+
# Main routine
84+
case "${1}" in
85+
"${COMPARTMENT_ID_COMMAND}")
86+
get_compartment_id
87+
;;
88+
"${COMPARTMENT_NAME_COMMAND}")
89+
get_compartment_name
90+
;;
91+
"${CUSTOM_LOG_ID_COMMAND}")
92+
get_custom_log_id
93+
;;
94+
"${PUBLIC_IP_COMMAND}")
95+
get_public_ip
96+
;;
97+
"${CREATE_SSH_PRIVATE_KEY_COMMAND}")
98+
create_ssh_private_key
99+
;;
100+
"${ALL_COMMAND}")
101+
left_justified_size=19
102+
print_resource ${COMPARTMENT_ID_COMMAND} "$(get_compartment_id)" ${left_justified_size}
103+
print_resource ${COMPARTMENT_NAME_COMMAND} "$(get_compartment_name)" ${left_justified_size}
104+
print_resource ${CUSTOM_LOG_ID_COMMAND} "$(get_custom_log_id)" ${left_justified_size}
105+
print_resource ${PUBLIC_IP_COMMAND} "$(get_public_ip)" ${left_justified_size}
106+
;;
107+
*)
108+
display_help
109+
;;
110+
esac

hols/oci-basic-setup/get_common.sh

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/bin/bash
2+
#
3+
# Copyright (c) 2025 Oracle and/or its affiliates.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
# Extracts resource value from terraform state
19+
get_resource_value() {
20+
parse_tf_output "${1}"
21+
}
22+
23+
# Parses resource from terraform state output
24+
parse_tf_output() {
25+
local resource
26+
resource=$(jq -r '.outputs.'"${1}"'.value' "${TERRAFORM_TFSTATE}")
27+
evaluate_parsed_resource "${resource}"
28+
}
29+
30+
# Evaluate if parsed resource is empty or not
31+
evaluate_parsed_resource() {
32+
if [[ -n "${1}" && "${1}" != "null" ]]; then
33+
echo -n "${1}"
34+
else
35+
echo -n "Requested oci resource does not exist"
36+
fi
37+
}
38+
39+
print_command_detail() {
40+
local key=${1}
41+
local description=${2}
42+
local key_left_justified_size=${3}
43+
printf ' %-'"${key_left_justified_size}"'s' "${key}"
44+
echo "${description}"
45+
}
46+
47+
print_resource() {
48+
local key=${1}
49+
local description=${2}
50+
local key_left_justified_size=${3}
51+
printf '%-'"${key_left_justified_size}"'s: ' "${key}"
52+
echo "${description}"
53+
}
54+
55+
if ! test -f "${TERRAFORM_TFSTATE}"; then
56+
echo "Error: Terraform state (\"${TERRAFORM_TFSTATE}\") does not exist which means the oci resource(s) have not been provisioned yet"
57+
exit 1
58+
fi
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#cloud-config
2+
# Open port 8080 for the Helidon application
3+
runcmd:
4+
- echo "Begin firewall port 8080 update" > /var/log/firewall-update.log
5+
- firewall-offline-cmd --add-port=8080/tcp &>> /var/log/firewall-update.log
6+
- systemctl restart firewalld &>> /var/log/firewall-update.log
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#
2+
# Copyright (c) 2025 Oracle and/or its affiliates.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
17+
# Provisions a compute instance that will be used as the deployment target
18+
resource "oci_core_instance" "compute_instance" {
19+
availability_domain = var.availablity_domain_name == "" ? data.oci_identity_availability_domains.ads.availability_domains[0]["name"] : var.availablity_domain_name
20+
compartment_id = var.compartment_ocid
21+
display_name = "instance${var.resource_name_suffix}"
22+
shape = var.instance_shape
23+
fault_domain = "FAULT-DOMAIN-1"
24+
25+
shape_config {
26+
ocpus = var.instance_ocpus
27+
memory_in_gbs = var.instance_shape_config_memory_in_gbs
28+
}
29+
30+
metadata = {
31+
ssh_authorized_keys = var.ssh_public_key == "" ? tls_private_key.public_private_key_pair.public_key_openssh : var.ssh_public_key
32+
user_data = base64encode(file("./instance/cloud_init"))
33+
}
34+
35+
create_vnic_details {
36+
subnet_id = oci_core_subnet.subnet.id
37+
display_name = "primaryvnic${var.resource_name_suffix}"
38+
assign_public_ip = true
39+
assign_private_dns_record = true
40+
}
41+
42+
source_details {
43+
source_type = "image"
44+
source_id = lookup(data.oci_core_images.compute_instance_images.images[0], "id")
45+
boot_volume_size_in_gbs = "50"
46+
}
47+
48+
timeouts {
49+
create = "60m"
50+
}
51+
}

0 commit comments

Comments
 (0)