Adding MariaDB support to C++ Dev Container (#1241)

This commit is contained in:
Kanishk Tantia 2022-01-24 09:25:03 -05:00 коммит произвёл GitHub
Родитель 7c6917c483
Коммит 2e31d04943
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
15 изменённых файлов: 667 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,5 @@
MARIADB_ROOT_PASSWORD=mariadb
MARIADB_DATABASE=mariadb
MARIADB_USER=mariadb
MARIADB_PASSWORD=mariadb
MARIADB_HOSTNAME=localhost

Просмотреть файл

@ -0,0 +1,11 @@
# [Choice] Debian / Ubuntu version (use Debian 11/9, Ubuntu 18.04/21.04 on local arm64/Apple Silicon): debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04
ARG VARIANT=debian-11
FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-${VARIANT}
# Everything below this is needed for installing MariaDB
# Instructions are copied and modified from: https://mariadb.com/docs/clients/mariadb-connectors/connector-cpp/install/
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install curl
COPY ./install-mariadb.sh /
RUN chmod +x /install-mariadb.sh && ./install-mariadb.sh

Просмотреть файл

@ -0,0 +1,26 @@
{
"name": "C++ and MariaDB",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
// Set *default* container specific settings.json values on container create.
"settings": {},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-vscode.cpptools",
"ms-vscode.cmake-tools",
"ms-vscode.cpptools-extension-pack",
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// This is the recommended way to access the container from the host
// "forwardPorts": [3306],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "gcc -v",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode"
}

Просмотреть файл

@ -0,0 +1,48 @@
version: '3.8'
volumes:
mariadb-data:
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
# Update 'VARIANT' to pick a version of CPP
# See the README for more information on available versions.
VARIANT: debian-11
env_file:
- .env
# Security Opt and cap_add allow for C++ based debuggers to work.
# See `runArgs`: https://github.com/Microsoft/vscode-docs/blob/main/docs/remote/devcontainerjson-reference.md
# security_opt:
# - seccomp:unconfined
# cap_add:
# - SYS_PTRACE
volumes:
- ..:/workspace:cached
# Overrides default command so things don't shut down after the process ends.
command: sleep infinity
# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
network_mode: service:db
# Uncomment the next line to use a non-root user for all processes.
# user: vscode
# Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
# (Adding the "ports" property to this file will not forward from a Codespace.)
db:
image: mariadb:10.3.32-focal
restart: unless-stopped
volumes:
- mariadb-data:/var/lib/MARIADB
env_file:
- .env
# Add "forwardPorts": ["3306"] to **devcontainer.json** to forward DB locally.
# (Adding the "ports" property to this file will not forward from a Codespace.)

Просмотреть файл

@ -0,0 +1,88 @@
#!/bin/bash
set -e
OSURL=""
OSTAG=""
find_os_props() {
. /etc/os-release
case $ID in
debian)
case $VERSION_CODENAME in
stretch)
OSTAG="1683458"
OSURL="debian-9-stretch-amd64"
;;
*)
OSTAG="1683461"
OSURL="debian-buster-amd64"
;;
esac
;;
ubuntu)
case $VERSION_CODENAME in
bionic)
OSTAG="1683439"
OSURL="ubuntu-bionic-amd64"
;;
groovy)
OSTAG="1683454"
OSURL="ubuntu-groovy-amd64"
;;
*)
OSTAG="1683444"
OSURL="ubuntu-focal-amd64"
;;
esac
;;
*)
echo "Unsupported OS choice."
exit 1
;;
esac
}
MARIADB_REPO_SETUP=mariadb_repo_setup
MARIADB_REPO_SETUP_SHA256=mariadb_repo_setup.sha256
TMP_DIR=$(mktemp -d -t maria-XXXXXXXXXX)
MARIADB_CONNECTOR=""
cleanup() {
EXIT_CODE=$?
set +e
if [[ -n ${TMP_DIR} ]]; then
cd /
rm -rf ${TMP_DIR}
fi
exit $EXIT_CODE
}
trap cleanup EXIT
#Set up external repository and install C Connector
cd ${TMP_DIR}
curl -Ls "https://downloads.mariadb.com/MariaDB/${MARIADB_REPO_SETUP}" -o ${MARIADB_REPO_SETUP}
curl -Ls "https://downloads.mariadb.com/MariaDB/${MARIADB_REPO_SETUP_SHA256}" -o ${MARIADB_REPO_SETUP_SHA256}
sha256sum -c ${MARIADB_REPO_SETUP_SHA256}
chmod +x ${MARIADB_REPO_SETUP}
./${MARIADB_REPO_SETUP} --mariadb-server-version="mariadb-10.6"
apt install -y libmariadb3 libmariadb-dev
#Depending on the OS, install different C++ connectors
find_os_props
# Instructions are copied and modified from: https://mariadb.com/docs/clients/mariadb-connectors/connector-cpp/install/
MARIADB_CONNECTOR=mariadb-connector-cpp-1.0.1-$OSURL
curl -Ls https://dlm.mariadb.com/$OSTAG/connectors/cpp/connector-cpp-1.0.1/${MARIADB_CONNECTOR}.tar.gz -o ${MARIADB_CONNECTOR}.tar.gz
tar -xvzf ${MARIADB_CONNECTOR}.tar.gz && cd ${MARIADB_CONNECTOR}
install -d /usr/include/mariadb/conncpp
#Header Files being copied into the necessary directories
cp -R ./include/mariadb/* /usr/include/mariadb/
cp -R ./include/mariadb/conncpp/* /usr/include/mariadb/conncpp
cp -R ./include/mariadb/conncpp/compat/* /usr/include/mariadb/conncpp/compat
install -d /usr/lib/mariadb
install -d /usr/lib/mariadb/plugin
#Shared libraries copied into usr/lib
cp lib/mariadb/libmariadbcpp.so /usr/lib
cp -R lib/mariadb/plugin/* /usr/lib/mariadb/plugin

35
containers/cpp-mariadb/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,35 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# build dir
build/

Просмотреть файл

@ -0,0 +1,7 @@
README.md
test-project
history
definition-manifest.json
library-scripts
.vscode
.npmignore

28
containers/cpp-mariadb/.vscode/launch.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1,28 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Main",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/test-project/main.out",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}/test-project",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "Build Main"
}
]
}

45
containers/cpp-mariadb/.vscode/settings.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1,45 @@
{
"files.associations": {
"*.psm": "powershell",
"iostream": "cpp",
"array": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"concepts": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"list": "cpp",
"map": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"functional": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"limits": "cpp",
"memory": "cpp",
"new": "cpp",
"optional": "cpp",
"ostream": "cpp",
"ranges": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"type_traits": "cpp",
"tuple": "cpp",
"typeinfo": "cpp",
"utility": "cpp"
},
"cmake.sourceDirectory": "${workspaceRoot}/test-project"
}

16
containers/cpp-mariadb/.vscode/tasks.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1,16 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Build Main",
"type": "shell",
"command": " cd test-project && g++ -g main.cpp -o main.out -lmariadbcpp",
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

Просмотреть файл

@ -0,0 +1,115 @@
# C++ & MariaDB
## Summary
*Develop C++ applications on Linux. Includes Debian C++ build tools.*
| Metadata | Value |
|----------|-------|
| *Contributors* | The VS Code Team |
| *Categories* | Core, Languages |
| *Definition type* | Docker Compose |
| *Available image variants* | [See cpp definition](../cpp). |
| *Supported architecture(s)* | x86-64, aarch64/arm64 for `bullseye`, `stretch`, `bionic`, and `hirsute` variants |
| *Works in Codespaces* | Yes |
| *Container host OS support* | Linux, macOS, Windows |
| *Container OS* | Debian, Ubuntu |
| *Languages, platforms* | C++ |
## Using this definition
This definition creates two containers, one for C++ and one for MariaDB (MySQL). VS Code will attach to the C++ dev container, and from within that container the MariaDB container will be available on **`localhost`** port 3306. The `.env` file sets the default credentials for the MariaDB Database. The default database is named `mariadb` with a user of `mariadb` whose password is `mariadb`, and if desired this may be changed in `.env`. Data is stored in a volume named `mariadb-data`.
While the definition itself works unmodified, you can select the version of Debian or Ubuntu the container uses by updating the `VARIANT` arg in `.devcontainer/docker-compose.yml` (and rebuilding if you've already created the container).
```yaml
build:
context: .
dockerfile: Dockerfile
args:
# Update 'VARIANT' to pick a version of CPP
# See the README for more information on available versions.
VARIANT: debian-11
```
Beyond `git`, this image / `Dockerfile` includes `zsh`, [Oh My Zsh!](https://ohmyz.sh/), a non-root `vscode` user with `sudo` access, and a set of common dependencies for development.
### Adding the definition to a project or codespace
1. If this is your first time using a development container, please see getting started information on [setting up](https://aka.ms/vscode-remote/containers/getting-started) Remote-Containers or [creating a codespace](https://aka.ms/ghcs-open-codespace) using GitHub Codespaces.
2. Start VS Code and open your project folder or connect to a codespace.
3. Press <kbd>F1</kbd> select and **Add Development Container Configuration Files...** command for **Remote-Containers** or **Codespaces**.
> **Note:** If needed, you can drag-and-drop the `.devcontainer` folder from this sub-folder in a locally cloned copy of this repository into the VS Code file explorer instead of using the command.
4. Select this definition. You may also need to select **Show All Definitions...** for it to appear.
5. Finally, press <kbd>F1</kbd> and run **Remote-Containers: Reopen Folder in Container** or **Codespaces: Rebuild Container** to start using the definition.
## Using the MariaDB Database
You can connect to MariaDB from an external tool when using VS Code by updating `.devcontainer/devcontainer.json` as follows:
```json
"forwardPorts": [ "3306" ]
```
Once the MariaDB container has port forwarding enabled, it will be accessible from the Host machine at `localhost:3306`. The [MariaDB Documentation](https://mariadb.com/docs/) has:
1. [An Installation Guide for MySQL](https://mariadb.com/kb/en/mysql-client/), a CLI tool to work with a MariaDB database.
2. [Tips on populating data](https://mariadb.com/kb/en/how-to-quickly-insert-data-into-mariadb/) in the database.
If needed, you can use `postCreateCommand` to run commands after the container is created, by updating `.devcontainer/devcontainer.json` similar to what follows:
```json
"postCreateCommand": "g++ --version && git --version"
```
### Adding another service
You can add other services to your `docker-compose.yml` file [as described in Docker's documentation](https://docs.docker.com/compose/compose-file/#service-configuration-reference). However, if you want anything running in this service to be available in the container on localhost, or want to forward the service locally, be sure to add this line to the service config:
```yaml
# Runs the service on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
network_mode: service:[$SERVICENAME]
```
## Testing the definition
This definition includes some test code that will help you verify it is working as expected on your system. Follow these steps:
1. If this is your first time using a development container, please follow the [getting started steps](https://aka.ms/vscode-remote/containers/getting-started) to set up your machine.
2. Clone this repository.
3. Start VS Code, press <kbd>F1</kbd>, and select **Remote-Containers: Open Folder in Container...**
4. Select the `containers/cpp-mariadb` folder.
5. After the folder has opened in the container, press <kbd>F5</kbd> to start the project.
6. You should see the following in the a terminal window after the program finishes executing.
```
Hello, Remote World!
DB Connecting
DB Executing
Cluster has the following user created databases
mariadb
DB Success
```
7. You can also run [test.sh](test-project/test.sh) in order to build and test the project.
8. From here, you can add breakpoints or edit the contents of the `test-project` folder to do further testing.
### Debugging Security
To allow C++ based debuggers to run within the Docker Containers, the [docker-compose.yml](.devcontainer/docker-compose.yml) contains the following lines which can be uncommented::
```yaml
security_opt:
- seccomp:unconfined
cap_add:
- SYS_PTRACE
```
As these can create security vulnerabilities, it is advisable to not use this unless needed. This should only be used in a Debug or Dev container, not in Production.
## License
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License. See [LICENSE](https://github.com/microsoft/vscode-dev-containers/blob/main/LICENSE).

Просмотреть файл

@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.0.0)
project(test-project VERSION 0.1.0)
include(CTest)
enable_testing()
add_executable(test-project main.cpp)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

Просмотреть файл

@ -0,0 +1,59 @@
/*-------------------------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
*-------------------------------------------------------------------------------------------------------------*/
#include <iostream>
#include <cassert>
#include <mariadb/conncpp.hpp>
using namespace std;
int main()
{
cout << "Hello, Remote World!" << endl;
char *databasename = getenv("MARIADB_DATABASE");
assert(databasename != NULL);
char *password = getenv("MARIADB_PASSWORD");
assert(password != NULL);
char *username = getenv("MARIADB_USER");
assert(username != NULL);
char *hostname = getenv("MARIADB_HOSTNAME");
assert(hostname != NULL);
string jointURL = "jdbc:mariadb://" + string(hostname) + "/" + string(databasename);
// Configure Connection
sql::SQLString url(jointURL);
sql::Properties properties({{"user", string(username)},
{"password", string(password)}});
// Establish Connection
cout << "DB Connecting" << endl;
try
{
unique_ptr<sql::Connection> conn(sql::DriverManager::getConnection(url, properties));
string query = "show databases "
"where `database` not in "
"('information_schema', 'performance_schema');";
cout << "DB Executing Query" << endl;
unique_ptr<sql::Statement> stmnt(conn->createStatement());
unique_ptr<sql::ResultSet> res(stmnt->executeQuery(query));
cout << "Listing user created databases" << endl;
while(res->next())
{
cout << res->getString(1) << endl;
}
conn->close();
}
catch(const sql::SQLException& e)
{
cerr << "Error Connecting to MariaDB Platform: " << e.what() << endl;
return 1;
}
return 0;
}

Просмотреть файл

@ -0,0 +1,149 @@
#!/bin/bash
SCRIPT_FOLDER="$(cd "$(dirname $0)" && pwd)"
USERNAME=${1:-vscode}
if [ -z $HOME ]; then
HOME="/root"
fi
FAILED=()
echoStderr()
{
echo "$@" 1>&2
}
check() {
LABEL=$1
shift
echo -e "\n🧪 Testing $LABEL"
if "$@"; then
echo "✅ Passed!"
return 0
else
echoStderr "$LABEL check failed."
FAILED+=("$LABEL")
return 1
fi
}
checkMultiple() {
PASSED=0
LABEL="$1"
echo -e "\n🧪 Testing $LABEL."
shift; MINIMUMPASSED=$1
shift; EXPRESSION="$1"
while [ "$EXPRESSION" != "" ]; do
if $EXPRESSION; then ((PASSED++)); fi
shift; EXPRESSION=$1
done
if [ $PASSED -ge $MINIMUMPASSED ]; then
echo "✅ Passed!"
return 0
else
echoStderr "$LABEL check failed."
FAILED+=("$LABEL")
return 1
fi
}
checkOSPackages() {
LABEL=$1
shift
echo -e "\n🧪 Testing $LABEL"
if dpkg-query --show -f='${Package}: ${Version}\n' "$@"; then
echo "✅ Passed!"
return 0
else
echoStderr "$LABEL check failed."
FAILED+=("$LABEL")
return 1
fi
}
checkExtension() {
# Happens asynchronusly, so keep retrying 10 times with an increasing delay
EXTN_ID="$1"
TIMEOUT_SECONDS="${2:-10}"
RETRY_COUNT=0
echo -e -n "\n🧪 Looking for extension $1 for maximum of ${TIMEOUT_SECONDS}s"
until [ "${RETRY_COUNT}" -eq "${TIMEOUT_SECONDS}" ] || \
[ ! -e $HOME/.vscode-server/extensions/${EXTN_ID}* ] || \
[ ! -e $HOME/.vscode-server-insiders/extensions/${EXTN_ID}* ] || \
[ ! -e $HOME/.vscode-test-server/extensions/${EXTN_ID}* ] || \
[ ! -e $HOME/.vscode-remote/extensions/${EXTN_ID}* ]
do
sleep 1s
(( RETRY_COUNT++ ))
echo -n "."
done
if [ ${RETRY_COUNT} -lt ${TIMEOUT_SECONDS} ]; then
echo -e "\n✅ Passed!"
return 0
else
echoStderr -e "\n❌ Extension $EXTN_ID not found."
FAILED+=("$LABEL")
return 1
fi
}
checkCommon()
{
PACKAGE_LIST="apt-utils \
git \
openssh-client \
less \
iproute2 \
procps \
curl \
wget \
unzip \
nano \
jq \
lsb-release \
ca-certificates \
apt-transport-https \
dialog \
gnupg2 \
libc6 \
libgcc1 \
libgssapi-krb5-2 \
liblttng-ust0 \
libstdc++6 \
zlib1g \
locales \
sudo"
# Actual tests
checkOSPackages "common-os-packages" ${PACKAGE_LIST}
checkMultiple "vscode-server" 1 "[ -d $HOME/.vscode-server/bin ]" "[ -d $HOME/.vscode-server-insiders/bin ]" "[ -d $HOME/.vscode-test-server/bin ]" "[ -d $HOME/.vscode-remote/bin ]" "[ -d $HOME/.vscode-remote/bin ]"
check "non-root-user" id ${USERNAME}
check "locale" [ $(locale -a | grep en_US.utf8) ]
check "sudo" sudo echo "sudo works."
check "zsh" zsh --version
check "oh-my-zsh" [ -d "$HOME/.oh-my-zsh" ]
check "login-shell-path" [ -f "/etc/profile.d/00-restore-env.sh" ]
check "code" which code
}
reportResults() {
if [ ${#FAILED[@]} -ne 0 ]; then
echoStderr -e "\n💥 Failed tests: ${FAILED[@]}"
exit 1
else
echo -e "\n💯 All passed!"
exit 0
fi
}
fixTestProjectFolderPrivs() {
if [ "${USERNAME}" != "root" ]; then
TEST_PROJECT_FOLDER="${1:-$SCRIPT_FOLDER}"
FOLDER_USER="$(stat -c '%U' "${TEST_PROJECT_FOLDER}")"
if [ "${FOLDER_USER}" != "${USERNAME}" ]; then
echoStderr "WARNING: Test project folder is owned by ${FOLDER_USER}. Updating to ${USERNAME}."
sudo chown -R ${USERNAME} "${TEST_PROJECT_FOLDER}"
fi
fi
}

Просмотреть файл

@ -0,0 +1,24 @@
#!/bin/bash
cd $(dirname "$0")
source test-utils.sh vscode
# Run common tests
checkCommon
# Run definition specific tests
checkExtension "ms-vscode.cpptools"
checkExtension "ms-vscode.cmake-tools"
checkExtension "ms-vscode.cpptools-extension-pack"
checkOSPackages "command-line-tools" build-essential cmake cppcheck valgrind clang lldb llvm gdb
check "g++" g++ -g main.cpp -o main.out -lmariadbcpp
check "main.out" ./main.out
rm main.out
mkdir -p build
cd build
check "cmake" cmake ..
cd ..
rm -rf build
## Report result
reportResults