diff --git a/deployment/edge/ansible/README.md b/deployment/edge/ansible/README.md deleted file mode 100644 index 3d6ab25c..00000000 --- a/deployment/edge/ansible/README.md +++ /dev/null @@ -1,20 +0,0 @@ -Before launching ansible export a env to specify your local vio directory -``` -export LOCAL_VIO_DIR= -``` - - -### Install sshpass -https://stackoverflow.com/questions/42835626/ansible-to-use-the-ssh-connection-type-with-passwords-you-must-install-the-s - -``` -pip install -r requirements.txt -``` - -## docker-compose devices - -We are adding those devices to be able to trigger capture from 2 cameras connected on the usb port of your edge. - -devices: - - /dev/video0:/dev/video0 - - /dev/video2:/dev/video2 \ No newline at end of file diff --git a/deployment/edge/aws/ansible/.python-version b/deployment/edge/aws/ansible/.python-version new file mode 100644 index 00000000..902b2c90 --- /dev/null +++ b/deployment/edge/aws/ansible/.python-version @@ -0,0 +1 @@ +3.11 \ No newline at end of file diff --git a/deployment/edge/ansible/Makefile b/deployment/edge/aws/ansible/Makefile similarity index 100% rename from deployment/edge/ansible/Makefile rename to deployment/edge/aws/ansible/Makefile diff --git a/deployment/edge/aws/ansible/README.md b/deployment/edge/aws/ansible/README.md new file mode 100644 index 00000000..8efcfc08 --- /dev/null +++ b/deployment/edge/aws/ansible/README.md @@ -0,0 +1,34 @@ +# Ansible repo to setup remote devices + +## Setup the remote devices passwordless using SSH + +- Set the different host devices inside the [inventory.ini](inventory.ini) providing user and password. +- Generate a public and private SSH key if you don't already have one using `ssh-keygen -t rsa -b 4096 -C "comment|email"` command. +- Define the `SSH_PUB_KEY_PATH` environment variable as the path to your SSH public key +- Run the following playbook: +```shell +ansible-playbook -i inventory.ini playbook/setup_ssh_key.yml +``` + +## Define local vio directory + +Before launching ansible export a env to specify your local vio directory +``` +export LOCAL_VIO_DIR= +``` + + +### Install sshpass +https://stackoverflow.com/questions/42835626/ansible-to-use-the-ssh-connection-type-with-passwords-you-must-install-the-s + +``` +pip install -r requirements.txt +``` + +## docker-compose devices + +We are adding those devices to be able to trigger capture from 2 cameras connected on the usb port of your edge. + +devices: + - /dev/video0:/dev/video0 + - /dev/video2:/dev/video2 \ No newline at end of file diff --git a/deployment/edge/ansible/files/docker-compose.template.yml b/deployment/edge/aws/ansible/files/docker-compose.template.yml similarity index 100% rename from deployment/edge/ansible/files/docker-compose.template.yml rename to deployment/edge/aws/ansible/files/docker-compose.template.yml diff --git a/deployment/edge/aws/ansible/inventories/group_vars/all.yml b/deployment/edge/aws/ansible/inventories/group_vars/all.yml new file mode 100644 index 00000000..550e0d0f --- /dev/null +++ b/deployment/edge/aws/ansible/inventories/group_vars/all.yml @@ -0,0 +1,18 @@ +--- + +aws_access_key_id: "{{ lookup('env', 'AWS_ACCESS_KEY_ID') }}" +aws_secret_access_key: "{{ lookup('env', 'AWS_SECRET_ACCESS_KEY') }}" +aws_session_token: "{{ lookup('env', 'AWS_SESSION_TOKEN') }}" + +aws_iot_greengrass_core_software: greengrass-nucleus-latest.zip +aws_iot_greengrass_group: ggc_group +aws_iot_greengrass_user: ggc_user +aws_iot_greengrass_password: "{{ lookup('env', 'AWS_IOT_GREENGRASS_PASSWORD') }}" +greengrass_aws_region: eu-west-1 +greengrass_root_dir: /greengrass/v2/ + +greengrass_thing_name: bapo-raspberry +greengrass_thing_group_name: bapo-group +greengrass_thing_policy_name: bapo-greengrass-policy +greengrass_iam_tmp_role_name: bapo-iam-role-for-greengrass +greengrass_iam_tmp_role_alias_name: bapo-iam-role-alias-for-greengrass \ No newline at end of file diff --git a/deployment/edge/ansible/inventory.ini b/deployment/edge/aws/ansible/inventories/hosts similarity index 88% rename from deployment/edge/ansible/inventory.ini rename to deployment/edge/aws/ansible/inventories/hosts index 972f7d31..4f1eb5d9 100644 --- a/deployment/edge/ansible/inventory.ini +++ b/deployment/edge/aws/ansible/inventories/hosts @@ -1,3 +1,6 @@ +[edge_0] +192.168.1.87 ansible_user=pi + [edge_1] 10.103.252.192 ansible_user=devkit ansible_password=devkit diff --git a/deployment/edge/ansible/deploy_vio_on_edge.yml b/deployment/edge/aws/ansible/playbooks/deploy_vio_on_edge.yml similarity index 100% rename from deployment/edge/ansible/deploy_vio_on_edge.yml rename to deployment/edge/aws/ansible/playbooks/deploy_vio_on_edge.yml diff --git a/deployment/edge/aws/ansible/playbooks/setup_the_device_environment_for_aws_iot_greengrass_core_software.yml b/deployment/edge/aws/ansible/playbooks/setup_the_device_environment_for_aws_iot_greengrass_core_software.yml new file mode 100644 index 00000000..c9a4202e --- /dev/null +++ b/deployment/edge/aws/ansible/playbooks/setup_the_device_environment_for_aws_iot_greengrass_core_software.yml @@ -0,0 +1,24 @@ +- name: "Set up the device environment for AWS IoT Greengrass Core software" + hosts: all + roles: + - role: roles/check_env_vars + vars: + env_vars: [SSH_PUB_KEY_PATH, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_IOT_GREENGRASS_PASSWORD] + - role: roles/setup_device_in_passwordless_mode_with_ssh + - role: roles/install_required_tools + - role: roles/create_user_for_aws_iot_greengrass + become: true + - role: staticdev.pyenv + vars: + pyenv_env: 'user' + pyenv_global: ["3.9"] + pyenv_python_versions: ["3.9"] + pyenv_enable_autocompletion: true + pyenv_owner: "{{ aws_iot_greengrass_user }}" + pyenv_owner_group: "{{ aws_iot_greengrass_group }}" + pyenv_path: "/home/{{ aws_iot_greengrass_user }}/.pyenv" + - role: roles/download_aws_iot_greengrass_core_software + remote_user: root + - role: roles/install_aws_iot_greengrass_core_software + - role: roles/install_docker + become: true diff --git a/deployment/edge/ansible/requirements.txt b/deployment/edge/aws/ansible/requirements.txt similarity index 100% rename from deployment/edge/ansible/requirements.txt rename to deployment/edge/aws/ansible/requirements.txt diff --git a/deployment/edge/aws/ansible/requirements.yml b/deployment/edge/aws/ansible/requirements.yml new file mode 100644 index 00000000..d028dad1 --- /dev/null +++ b/deployment/edge/aws/ansible/requirements.yml @@ -0,0 +1,5 @@ +# requirements.yml +--- + +roles: +- name: staticdev.pyenv diff --git a/deployment/edge/aws/ansible/roles/check_env_vars/tasks/main.yml b/deployment/edge/aws/ansible/roles/check_env_vars/tasks/main.yml new file mode 100644 index 00000000..4a4a2584 --- /dev/null +++ b/deployment/edge/aws/ansible/roles/check_env_vars/tasks/main.yml @@ -0,0 +1,11 @@ +--- + +- name: Check credentials are set as environment variables + assert: + that: + - "{{ lookup('env', item) is defined }}" + - "{{ lookup('env', item) | length > 0 }}" + - "{{ lookup('env', item) != None }}" + fail_msg: "{{ item }} environment variable needs to be set for the role to work" + success_msg: "Required variable {{ item }} is defined" + loop: "{{ env_vars }}" diff --git a/deployment/edge/aws/ansible/roles/create_user_for_aws_iot_greengrass/tasks/main.yml b/deployment/edge/aws/ansible/roles/create_user_for_aws_iot_greengrass/tasks/main.yml new file mode 100644 index 00000000..f7653a93 --- /dev/null +++ b/deployment/edge/aws/ansible/roles/create_user_for_aws_iot_greengrass/tasks/main.yml @@ -0,0 +1,40 @@ +--- + +- name: Ensure group "{{ aws_iot_greengrass_group }}" exists + ansible.builtin.group: + name: "{{ aws_iot_greengrass_group }}" + state: present + +- name: Add the user "{{ aws_iot_greengrass_user }}" with a primary group of "{{ aws_iot_greengrass_group }}" + ansible.builtin.user: + name: "{{ aws_iot_greengrass_user }}" + group: "{{ aws_iot_greengrass_group }}" + password: "{{ aws_iot_greengrass_password }}" + create_home: yes + expires: -1 + update_password: always + +- name: Change "{{ aws_iot_greengrass_user }}" password + ansible.builtin.shell: "chage --list {{ aws_iot_greengrass_user }}" + +- name: Add the user "{{ aws_iot_greengrass_user }}" to docker group + ansible.builtin.user: + name: "{{ aws_iot_greengrass_user }}" + group: docker + +- name: Set authorized key taken from file + ansible.posix.authorized_key: + user: "{{ aws_iot_greengrass_user }}" + state: present + key: "{{ lookup('file', lookup('env','SSH_PUB_KEY_PATH')) }}" + +- name: Allow the "root" user to run any commands + community.general.sudoers: + name: allow-all-to-root + state: present + user: root + commands: ALL + +- name: Print /etc/sudoers file to check root permissions + ansible.builtin.shell: cat /etc/sudoers + become: true diff --git a/deployment/edge/aws/ansible/roles/download_aws_iot_greengrass_core_software/tasks/main.yml b/deployment/edge/aws/ansible/roles/download_aws_iot_greengrass_core_software/tasks/main.yml new file mode 100644 index 00000000..f2e14a56 --- /dev/null +++ b/deployment/edge/aws/ansible/roles/download_aws_iot_greengrass_core_software/tasks/main.yml @@ -0,0 +1,31 @@ +--- + +- name: Download the latest version of the AWS IoT Greengrass Core software + ansible.builtin.get_url: + url: https://d2s8p88vqu9w66.cloudfront.net/releases/{{ aws_iot_greengrass_core_software }} + dest: /tmp/{{ aws_iot_greengrass_core_software }} + +- name: Verify the Greengrass nucleus software signature + ansible.builtin.shell: jarsigner -verify -certs -verbose /tmp/{{ aws_iot_greengrass_core_software }} + register: resultVerification + failed_when: (resultVerification.stdout) == "jar is unsigned." + +- name: Create "/home/{{ aws_iot_greengrass_user }}/GreengrassInstaller" directory if it does not exist + ansible.builtin.file: + path: "/home/{{ aws_iot_greengrass_user }}/GreengrassInstaller" + state: directory + mode: '0755' + recurse: yes + owner: "{{ aws_iot_greengrass_user }}" + group: "{{ aws_iot_greengrass_group }}" + become: true + +- name: Unzip the AWS IoT Greengrass Core software to a folder + ansible.builtin.unarchive: + src: /tmp/{{ aws_iot_greengrass_core_software }} + dest: /home/{{ aws_iot_greengrass_user }}/GreengrassInstaller + remote_src: yes + become: true + +- name: See the version of the AWS IoT Greengrass Core software + ansible.builtin.shell: java -jar /home/{{ aws_iot_greengrass_user }}/GreengrassInstaller/lib/Greengrass.jar --version diff --git a/deployment/edge/aws/ansible/roles/install_aws_iot_greengrass_core_software/tasks/main.yml b/deployment/edge/aws/ansible/roles/install_aws_iot_greengrass_core_software/tasks/main.yml new file mode 100644 index 00000000..b9b6d83e --- /dev/null +++ b/deployment/edge/aws/ansible/roles/install_aws_iot_greengrass_core_software/tasks/main.yml @@ -0,0 +1,42 @@ +--- + +- name: "Get stats of on {{ greengrass_root_dir }} directory" + ansible.builtin.stat: + path: "{{ greengrass_root_dir }}" + register: gg_dir + +- name: "Get stats of on /etc/systemd/system/greengrass.service" + ansible.builtin.stat: + path: /etc/systemd/system/greengrass.service + register: gg_service_file + +- name: Install the AWS IoT Greengrass Core software + ansible.builtin.shell: | + java -Droot="{{ greengrass_root_dir }}" -Dlog.store=FILE \ + -jar ./GreengrassInstaller/lib/Greengrass.jar \ + --aws-region {{ greengrass_aws_region }} \ + --thing-name {{ greengrass_thing_name }} \ + --thing-group-name {{ greengrass_thing_group_name }} \ + --thing-policy-name {{ greengrass_thing_policy_name }} \ + --tes-role-name {{ greengrass_iam_tmp_role_name }} \ + --tes-role-alias-name {{ greengrass_iam_tmp_role_alias_name }} \ + --component-default-user {{ aws_iot_greengrass_user }}:{{ aws_iot_greengrass_group }} \ + --provision true \ + --setup-system-service true \ + --deploy-dev-tools true + args: + chdir: /home/{{ aws_iot_greengrass_user }} + become_user: root + become: true + environment: + AWS_ACCESS_KEY_ID: "{{ aws_access_key_id }}" + AWS_SECRET_ACCESS_KEY: "{{ aws_secret_access_key }}" + AWS_SESSION_TOKEN: "{{ aws_session_token }}" + when: not gg_dir.stat.exists and not gg_service_file.stat.exists + +- name: Enable service greengrass and ensure it is not masked + ansible.builtin.systemd_service: + name: greengrass + enabled: true + state: started + masked: no diff --git a/deployment/edge/aws/ansible/roles/install_docker/README.md b/deployment/edge/aws/ansible/roles/install_docker/README.md new file mode 100644 index 00000000..225dd44b --- /dev/null +++ b/deployment/edge/aws/ansible/roles/install_docker/README.md @@ -0,0 +1,38 @@ +Role Name +========= + +A brief description of the role goes here. + +Requirements +------------ + +Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. + +Role Variables +-------------- + +A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. + +Dependencies +------------ + +A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. + +Example Playbook +---------------- + +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: + + - hosts: servers + roles: + - { role: username.rolename, x: 42 } + +License +------- + +BSD + +Author Information +------------------ + +An optional section for the role authors to include contact information, or a website (HTML is not allowed). diff --git a/deployment/edge/aws/ansible/roles/install_docker/defaults/main.yml b/deployment/edge/aws/ansible/roles/install_docker/defaults/main.yml new file mode 100644 index 00000000..65923d85 --- /dev/null +++ b/deployment/edge/aws/ansible/roles/install_docker/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for install_docker diff --git a/deployment/edge/aws/ansible/roles/install_docker/files/docker-compose b/deployment/edge/aws/ansible/roles/install_docker/files/docker-compose new file mode 100644 index 00000000..cc77c739 --- /dev/null +++ b/deployment/edge/aws/ansible/roles/install_docker/files/docker-compose @@ -0,0 +1 @@ +docker compose "$@" diff --git a/deployment/edge/aws/ansible/roles/install_docker/handlers/main.yml b/deployment/edge/aws/ansible/roles/install_docker/handlers/main.yml new file mode 100644 index 00000000..58c758ae --- /dev/null +++ b/deployment/edge/aws/ansible/roles/install_docker/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for install_docker diff --git a/deployment/edge/aws/ansible/roles/install_docker/meta/main.yml b/deployment/edge/aws/ansible/roles/install_docker/meta/main.yml new file mode 100644 index 00000000..ea68190c --- /dev/null +++ b/deployment/edge/aws/ansible/roles/install_docker/meta/main.yml @@ -0,0 +1,34 @@ +galaxy_info: + author: your name + description: your role description + company: your company (optional) + + # If the issue tracker for your role is not on github, uncomment the + # next line and provide a value + # issue_tracker_url: http://example.com/issue/tracker + + # Choose a valid license ID from https://spdx.org - some suggested licenses: + # - BSD-3-Clause (default) + # - MIT + # - GPL-2.0-or-later + # - GPL-3.0-only + # - Apache-2.0 + # - CC-BY-4.0 + license: license (GPL-2.0-or-later, MIT, etc) + + min_ansible_version: 2.1 + + # If this a Container Enabled role, provide the minimum Ansible Container version. + # min_ansible_container_version: + + galaxy_tags: [] + # List tags for your role here, one per line. A tag is a keyword that describes + # and categorizes the role. Users find roles by searching for tags. Be sure to + # remove the '[]' above, if you add tags to this list. + # + # NOTE: A tag is limited to a single word comprised of alphanumeric characters. + # Maximum 20 tags per role. + +dependencies: [] + # List your role dependencies here, one per line. Be sure to remove the '[]' above, + # if you add dependencies to this list. diff --git a/deployment/edge/aws/ansible/roles/install_docker/tasks/main.yml b/deployment/edge/aws/ansible/roles/install_docker/tasks/main.yml new file mode 100644 index 00000000..ffc5566e --- /dev/null +++ b/deployment/edge/aws/ansible/roles/install_docker/tasks/main.yml @@ -0,0 +1,48 @@ +--- +# tasks file for install_docker + +- name: Create /etc/apt/keyrings + ansible.builtin.file: + path: /etc/apt/keyrings + state: directory + mode: '0755' + +- name: Add Docker GPG apt Key + ansible.builtin.get_url: + url: https://download.docker.com/linux/raspbian/gpg + dest: /etc/apt/keyrings/docker.asc + +- name: Add Docker Repository + apt_repository: + repo: "deb [arch=armhf signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/raspbian buster stable" + state: present + +- name: Update apt and install docker and useful plugins + apt: + name: "{{ item }}" + state: latest + update_cache: true + loop: [docker-ce, docker-ce-cli, containerd.io, docker-buildx-plugin, docker-compose-plugin] + +- name: Copy docker-compose file with owner and permissions + ansible.builtin.copy: + src: files/docker-compose + dest: /usr/bin/docker-compose + owner: root + group: root + mode: '0755' + +- name: Enable service docker and ensure it is not masked + ansible.builtin.systemd_service: + name: "{{ item }}" + enabled: true + state: restarted + masked: no + loop: ["docker", "containerd"] + +- name: Add user to docker group + user: + name: "{{ item }}" + groups: docker + append: yes + loop: ["pi", "{{ aws_iot_greengrass_user }}"] diff --git a/deployment/edge/aws/ansible/roles/install_docker/tests/inventory b/deployment/edge/aws/ansible/roles/install_docker/tests/inventory new file mode 100644 index 00000000..878877b0 --- /dev/null +++ b/deployment/edge/aws/ansible/roles/install_docker/tests/inventory @@ -0,0 +1,2 @@ +localhost + diff --git a/deployment/edge/aws/ansible/roles/install_docker/tests/test.yml b/deployment/edge/aws/ansible/roles/install_docker/tests/test.yml new file mode 100644 index 00000000..5ed773f6 --- /dev/null +++ b/deployment/edge/aws/ansible/roles/install_docker/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - install_docker diff --git a/deployment/edge/aws/ansible/roles/install_docker/vars/main.yml b/deployment/edge/aws/ansible/roles/install_docker/vars/main.yml new file mode 100644 index 00000000..9141382e --- /dev/null +++ b/deployment/edge/aws/ansible/roles/install_docker/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for install_docker diff --git a/deployment/edge/aws/ansible/roles/install_required_tools/files/useful_debian_packages b/deployment/edge/aws/ansible/roles/install_required_tools/files/useful_debian_packages new file mode 100644 index 00000000..13fc8c6e --- /dev/null +++ b/deployment/edge/aws/ansible/roles/install_required_tools/files/useful_debian_packages @@ -0,0 +1,26 @@ +acl +build-essential +curl +default-jdk +gcc +git +libbz2-dev +libffi-dev +liblzma-dev +libncurses5-dev +libncursesw5-dev +libreadline-dev +libsqlite3-dev +libssl-dev +libxml2-dev +libxmlsec1-dev +llvm +lsb-release +make +python3-openssl +python3-pip +tk-dev +xz-utils +vim +wget +zlib1g-dev diff --git a/deployment/edge/aws/ansible/roles/install_required_tools/tasks/main.yml b/deployment/edge/aws/ansible/roles/install_required_tools/tasks/main.yml new file mode 100644 index 00000000..5650ffef --- /dev/null +++ b/deployment/edge/aws/ansible/roles/install_required_tools/tasks/main.yml @@ -0,0 +1,22 @@ +--- + +- name: Install required packages on the device + apt: + name: "{{ item }}" + state: present + update_cache: yes + become: true + loop: "{{ lookup('file', 'files/useful_debian_packages').splitlines() }}" + +- name: Get the Java version + ansible.builtin.shell: java -version + register: java_version + +- name: Print the Java version + ansible.builtin.debug: + var: java_version + +- name: Upgrade Python pip + ansible.builtin.pip: + name: pip + state: latest diff --git a/deployment/edge/aws/ansible/roles/setup_device_in_passwordless_mode_with_ssh/tasks/main.yml b/deployment/edge/aws/ansible/roles/setup_device_in_passwordless_mode_with_ssh/tasks/main.yml new file mode 100644 index 00000000..e228e33e --- /dev/null +++ b/deployment/edge/aws/ansible/roles/setup_device_in_passwordless_mode_with_ssh/tasks/main.yml @@ -0,0 +1,7 @@ +--- + +- name: Set authorized key taken from file + ansible.posix.authorized_key: + user: pi + state: present + key: "{{ lookup('file', lookup('env','SSH_PUB_KEY_PATH')) }}" diff --git a/deployment/edge/aws/ansible/roles/uninstall_aws_iot_greengrass_core/tasks/main.yml b/deployment/edge/aws/ansible/roles/uninstall_aws_iot_greengrass_core/tasks/main.yml new file mode 100644 index 00000000..2ae38424 --- /dev/null +++ b/deployment/edge/aws/ansible/roles/uninstall_aws_iot_greengrass_core/tasks/main.yml @@ -0,0 +1,3 @@ +--- + +- \ No newline at end of file diff --git a/deployment/hub/aws/README.md b/deployment/hub/aws/README.md new file mode 100644 index 00000000..4892f3a6 --- /dev/null +++ b/deployment/hub/aws/README.md @@ -0,0 +1,168 @@ +# Getting Started + +## Step 1: Install AWS IoT Greengrass Core software with automatic resource provisioning on the edge device + +There are two possible ways of installing AWS Iot Greengrass Core software: + +- Manually following the [AWS documentation](https://docs.aws.amazon.com/greengrass/v2/developerguide/quick-installation.html) +- Automatically using Ansible + +> [!WARNING] +> The installation with Ansible works for Unix OS **only**! + +### Add the IP of your device to the Ansible inventory + +Open the [Ansible inventory file](../../edge/aws/ansible/inventories/hosts) and add your device in it. + +### Run the playbook to install all required softwares automatically on your device + +Go to the folder and create yourself a Python virtual environment if you don't have any: +```shell +cd ../../edge/aws/ansible/ +python -m venv .venv +``` + +Activate the Python virtual environment and install the required libraries: +```shell +source .venv/bin/activate +pip install -r requirements.txt +``` + +Apply the Ansible playbook on your device to install all required softwares: +```shell +ansible-playbook -i inventories/hosts playbooks/setup_the_device_environment_for_aws_iot_greengrass_core_software.yml +``` + +## Step 2: Register your device to AWS + +Follow the [AWS documentation](https://docs.aws.amazon.com/iot/latest/developerguide/iot-quick-start.html) to register your device. + +## Step 3: Create the resources in AWS + +### Upload the components to S3 and ECR + +#### Create the AWS S3 bucket and upload the artifact + +Replace `AWS_ACCOUNT_ID` with your AWS account ID and `REGION` with the AWS Region: + +```shell +aws s3 mb s3://greengrass-component-artifacts-AWS_ACCOUNT_ID-REGION +aws s3 cp docker-compose.yml s3://greengrass-component-artifacts-AWS_ACCOUNT_ID-REGION/artifacts/1.0.0/docker-compose.yml +``` + +#### Create the AWS ECR repository + +Replace `AWS_ACCOUNT_ID` with your AWS account ID and `REGION` with the AWS Region: + +```shell +aws ecr create-repository --registry-id AWS_ACCOUNT_ID --region REGION --repository-name vio/file_uploader +``` + +#### Push the Docker image to ECR repository + +Replace `AWS_ACCOUNT_ID` with your AWS account ID and `REGION` with the AWS Region: + +```shell +aws ecr get-login-password --region REGION | docker login --username AWS --password-stdin AWS_ACCOUNT_ID.dkr.ecr.eu-west-1.amazonaws.com +docker build -t AWS_ACCOUNT_ID.dkr.ecr.eu-west-1.amazonaws.com/vio/file_uploader:latest +docker push AWS_ACCOUNT_ID.dkr.ecr.eu-west-1.amazonaws.com/vio/file_uploader:latest +``` + +### Allow the core device to access component artifacts in the S3 bucket and ECR + +#### Create the policy to access S3 and ECR + +```shell +aws iam create-policy \ + --policy-name MyGreengrassV2ComponentArtifactPolicy \ + --policy-document file://component-artifact-policy.json +``` + +#### Attach the policy to the core device role + +Replace GreengrassV2TokenExchangeRole with the name of the role for the core device: + +```shell +aws iam attach-role-policy \\ + --role-name GreengrassV2TokenExchangeRole \\ + --policy-arn arn:aws:iam::123456789012:policy/MyGreengrassV2ComponentArtifactPolicy +``` + +## Step 4: Create a component resource in AWS IoT Greengrass from the recipe + +### Add the artifact's Amazon S3 URI to the component recipe. + +Open the YAML recipe file [fu_recipe.yaml](../greengrassv2/fu_recipe.yaml) and update the line concerning the artifacts with: + +```yaml +Artifacts: + - URI: s3://greengrass-component-artifacts-AWS_ACCOUNT_ID-REGION/artifacts/1.0.0/docker-compose.yml +``` + +### Create the component resource in AWS IoT Greengrass from the recipe + +```shell +aws greengrassv2 create-component-version --inline-recipe fileb://recipes/fu_recipe.yaml +``` + +The response looks similar to the following example if the request succeeds. + +```json +{ + "arn": "arn:aws:greengrass:REGION:AWS_ACCOUNT_ID:components:file_uploader:versions:1.0.0", + "componentName": "file_uploader", + "componentVersion": "1.0.0", + "creationTimestamp": "Mon Nov 30 09:04:05 UTC 2020", + "status": { + "componentState": "REQUESTED", + "message": "NONE", + "errors": {} + } +} +``` + +Copy the `arn` from the output to check the state of the component and verify it is deployable. Replace the `ARN` with the one copied and type: + + +```shell +aws greengrassv2 describe-component --arn "arn:aws:greengrass:REGION:AWS_ACCOUNT_ID:components:file_uploader:versions:1.0.0" +``` + +If the component validates, the response indicates that the component state is DEPLOYABLE. + +```json +{ + "arn": "arn:aws:greengrass:REGION:AWS_ACCOUNT_ID:components:file_uploader:versions:1.0.0", + "componentName": "file_uploader", + "componentVersion": "1.0.0", + "creationTimestamp": "2020-11-30T18:04:05.823Z", + "publisher": "Amazon", + "description": "My first Greengrass component.", + "status": { + "componentState": "DEPLOYABLE", + "message": "NONE", + "errors": {} + }, + "platforms": [ + { + "os": "linux", + "architecture": "all" + } + ] +} +``` + + +## Step 5: Deploy the component + +Edit the JSON deployment file [deployment-revision-1-for-bapo-group.json](deployment-revision-1-for-bapo-group.json) to set correctly the bucket name and run the following command to deploy the component to your Greengrass core device replacing `MyGreengrassCore` with the name of the AWS IoT thing for your core device: + +```shell +aws greengrassv2 create-deployment \ + --target-arn "arn:aws:iot:REGION:AWS_ACCOUNT_ID:thing/MyGreengrassCore" \ + --cli-input-json file://deployment-revision-1-for-bapo-group.json +``` + +### Create a deployment + +Please refer to the [AWS documentation](https://docs.aws.amazon.com/greengrass/v2/developerguide/create-deployments.html). \ No newline at end of file diff --git a/deployment/hub/aws/aws-greengrass-labs-s3-file-uploader/deployment.json b/deployment/hub/aws/aws-greengrass-labs-s3-file-uploader/deployment.json new file mode 100644 index 00000000..2cffb980 --- /dev/null +++ b/deployment/hub/aws/aws-greengrass-labs-s3-file-uploader/deployment.json @@ -0,0 +1,34 @@ +{ + "targetArn": "arn:aws:iot:eu-west-1:767397954739:thinggroup/bapo-group", + "deploymentName": "Deploy FileWatcher for bapo-group", + "components": { + "aws.greengrass.Cli": { + "componentVersion": "2.12.6" + }, + "aws.greengrass.StreamManager": { + "componentVersion": "2.1.12" + }, + "aws.greengrass.TokenExchangeService": { + "componentVersion": "2.0.3" + }, + "aws.greengrass.labs.s3.file.uploader": { + "componentVersion": "1.1.0", + "configurationUpdate": { + "merge": "{\"PathName\": \"/home/ggc_user/watchdir/**/*.png\",\"BucketName\": \"bapo-greengrass-poc\",\"ObjectKeyPrefix\": \"watchdir/\",\"Interval\": \"1\",\"LogLevel\": \"INFO\"}" + } + } + }, + "deploymentPolicies": { + "failureHandlingPolicy": "DO_NOTHING", + "componentUpdatePolicy": { + "timeoutInSeconds": 60, + "action": "NOTIFY_COMPONENTS" + }, + "configurationValidationPolicy": { + "timeoutInSeconds": 60 + } + }, + "tags": { + "context": "poc-greengrass-by-bapo" + } +} \ No newline at end of file diff --git a/deployment/hub/aws/aws-greengrass-labs-s3-file-uploader/gdk-config.json b/deployment/hub/aws/aws-greengrass-labs-s3-file-uploader/gdk-config.json new file mode 100644 index 00000000..e79df5d1 --- /dev/null +++ b/deployment/hub/aws/aws-greengrass-labs-s3-file-uploader/gdk-config.json @@ -0,0 +1,16 @@ +{ + "component": { + "aws.greengrass.labs.s3.file.uploader": { + "author": "Amazon", + "version": "1.1.0", + "build": { + "build_system": "zip" + }, + "publish": { + "bucket": "bapo-greengrass-poc", + "region": "eu-west-1" + } + } + }, + "gdk_version": "1.0.0" +} \ No newline at end of file diff --git a/deployment/hub/aws/aws-greengrass-labs-s3-file-uploader/recipe.yaml b/deployment/hub/aws/aws-greengrass-labs-s3-file-uploader/recipe.yaml new file mode 100644 index 00000000..deff4b37 --- /dev/null +++ b/deployment/hub/aws/aws-greengrass-labs-s3-file-uploader/recipe.yaml @@ -0,0 +1,26 @@ +--- +RecipeFormatVersion: "2020-01-25" +ComponentName: "{COMPONENT_NAME}" +ComponentVersion: "{COMPONENT_VERSION}" +ComponentDescription: "This is simple file uploader component written in Python." +ComponentPublisher: "{COMPONENT_AUTHOR}" +ComponentDependencies: + aws.greengrass.StreamManager: + VersionRequirement: "^2.0.0" + DependencyType: "HARD" +ComponentConfiguration: + DefaultConfiguration: + PathName: "/home/ggc_user/watch_dir/*.png" + BucketName: "" + ObjectKeyPrefix: "watch_dir/" + Interval: "1" + LogLevel: "INFO" +Manifests: + - Platform: + os: linux + Artifacts: + - URI: "s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/aws-greengrass-labs-s3-file-uploader.zip" + Unarchive: ZIP + Lifecycle: + Run: "python3 -u {artifacts:decompressedPath}/aws-greengrass-labs-s3-file-uploader/main.py \"{configuration:/PathName}\" \"{configuration:/BucketName}\" \"{configuration:/ObjectKeyPrefix}\" \"{configuration:/Interval}\" \"{configuration:/LogLevel}\"" + Install: "pip3 install --user -r {artifacts:decompressedPath}/aws-greengrass-labs-s3-file-uploader/requirements.txt" \ No newline at end of file diff --git a/deployment/hub/aws/greengrassv2/.gitignore b/deployment/hub/aws/greengrassv2/.gitignore new file mode 100644 index 00000000..029e222f --- /dev/null +++ b/deployment/hub/aws/greengrassv2/.gitignore @@ -0,0 +1,10 @@ +*build/ +build +*dist/ +*.egg-info +*__pycache__ +*htmlcov/ +*.coverage +*.iml +*.DS_Store +*.eggs \ No newline at end of file diff --git a/deployment/hub/aws/greengrassv2/component-artifact-policy.json b/deployment/hub/aws/greengrassv2/component-artifact-policy.json new file mode 100644 index 00000000..e7571fa1 --- /dev/null +++ b/deployment/hub/aws/greengrassv2/component-artifact-policy.json @@ -0,0 +1,29 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "S3", + "Effect": "Allow", + "Action": [ + "s3:*", + "s3:GetObject" + ], + "Resource": [ + "*", + "arn:aws:s3:::bapo-greengrass-poc/*" + ] + }, + { + "Sid": "ECR", + "Effect": "Allow", + "Action": [ + "ecr:GetAuthorizationToken", + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer" + ], + "Resource": [ + "*" + ] + } + ] +} \ No newline at end of file diff --git a/deployment/hub/aws/greengrassv2/deployment-revision-1-for-bapo-group.json b/deployment/hub/aws/greengrassv2/deployment-revision-1-for-bapo-group.json new file mode 100644 index 00000000..028b6033 --- /dev/null +++ b/deployment/hub/aws/greengrassv2/deployment-revision-1-for-bapo-group.json @@ -0,0 +1,10 @@ +{ + "components": { + "file_uploader": { + "componentVersion": "1.0.0", + "configurationUpdate": { + "merge": "{\"bucketName\":\"BUCKET_NAME\"}" + } + } + } + } \ No newline at end of file diff --git a/deployment/hub/aws/greengrassv2/deployment.json b/deployment/hub/aws/greengrassv2/deployment.json new file mode 100644 index 00000000..5d36c776 --- /dev/null +++ b/deployment/hub/aws/greengrassv2/deployment.json @@ -0,0 +1,34 @@ +{ + "targetArn": "arn:aws:iot:eu-west-1:767397954739:thinggroup/bapo-group", + "deploymentName": "Deploy VIO for bapo-group", + "components": { + "aws.greengrass.Cli": { + "componentVersion": "2.12.6" + }, + "aws.greengrass.StreamManager": { + "componentVersion": "2.1.12" + }, + "aws.greengrass.TokenExchangeService": { + "componentVersion": "2.0.3" + }, + "aws.greengrass.DockerApplicationManager": { + "componentVersion": "2.0.11" + }, + "vio": { + "componentVersion": "0.1.4" + } + }, + "deploymentPolicies": { + "failureHandlingPolicy": "DO_NOTHING", + "componentUpdatePolicy": { + "timeoutInSeconds": 60, + "action": "NOTIFY_COMPONENTS" + }, + "configurationValidationPolicy": { + "timeoutInSeconds": 60 + } + }, + "tags": { + "context": "poc-greengrass-by-bapo" + } +} \ No newline at end of file diff --git a/deployment/hub/aws/greengrassv2/docker-compose.raspberrypi.yml b/deployment/hub/aws/greengrassv2/docker-compose.raspberrypi.yml new file mode 100644 index 00000000..0afbc387 --- /dev/null +++ b/deployment/hub/aws/greengrassv2/docker-compose.raspberrypi.yml @@ -0,0 +1,35 @@ +version: '3' + +services: + edge_db: + image: webhippie/mongodb:latest-arm32v7 + container_name: edge_db + ports: + - 27017:27017 + + edge_model_serving: + container_name: edge_model_serving + image: 767397954739.dkr.ecr.eu-west-1.amazonaws.com/edge_tflite_serving.raspberrypi:latest + environment: + - TF_CPP_MIN_VLOG_LEVEL=0 + ports: + - 8501:8501 + volumes: + - ./edge_model_serving:/models + + edge_orchestrator: + container_name: edge_orchestrator + image: 767397954739.dkr.ecr.eu-west-1.amazonaws.com/edge_orchestrator.raspberrypi:latest + privileged: true + volumes: + - ./edge_orchestrator/data:/edge_orchestrator/data + - ./edge_orchestrator/config:/edge_orchestrator/config + - /opt/vc:/opt/vc + ports: + - 8000:8000 + + edge_interface: + container_name: edge_interface + image: 767397954739.dkr.ecr.eu-west-1.amazonaws.com/edge_interface.raspberrypi:latest + ports: + - 8080:80 diff --git a/deployment/hub/aws/greengrassv2/fu_recipe.yaml b/deployment/hub/aws/greengrassv2/fu_recipe.yaml new file mode 100644 index 00000000..a9012472 --- /dev/null +++ b/deployment/hub/aws/greengrassv2/fu_recipe.yaml @@ -0,0 +1,30 @@ +--- +RecipeFormatVersion: '2020-01-25' +ComponentName: file_uploader +ComponentVersion: '1.0.0' +ComponentDescription: 'A component that uses Docker Compose to run images from public Amazon ECR and Docker Hub.' +ComponentPublisher: Amazon +ComponentDependencies: + aws.greengrass.DockerApplicationManager: + VersionRequirement: ~2.0.0 + DependencyType: HARD + aws.greengrass.TokenExchangeService: + VersionRequirement: ~2.0.0 + DependencyType: HARD +ComponentConfiguration: + DefaultConfiguration: + bucketName: 'bapo-greengrass-poc' +Manifests: + - Platform: + os: all + Lifecycle: + run: | + docker run \ + --network=host \ + -v ./monitored_dir:/monitored_dir \ + -e AWS_CONTAINER_AUTHORIZATION_TOKEN \ + -e AWS_CONTAINER_CREDENTIALS_FULL_URI \ + --rm AWS_ACCOUNT_ID.dkr.ecr.eu-west-1.amazonaws.com/vio/file_uploader:latest \ + "{configuration:/bucketName}" + Artifacts: + - URI: "docker:AWS_ACCOUNT_ID.dkr.ecr.eu-west-1.amazonaws.com/vio/file_uploader:latest" diff --git a/deployment/hub/aws/greengrassv2/vio_recipe.yaml b/deployment/hub/aws/greengrassv2/vio_recipe.yaml new file mode 100644 index 00000000..b6e4fac3 --- /dev/null +++ b/deployment/hub/aws/greengrassv2/vio_recipe.yaml @@ -0,0 +1,21 @@ +--- +RecipeFormatVersion: '2020-01-25' +ComponentName: vio +ComponentVersion: '0.1.3' +ComponentDescription: 'A component that uses Docker Compose to run images from public Amazon ECR and Docker Hub.' +ComponentPublisher: Amazon +ComponentDependencies: + aws.greengrass.DockerApplicationManager: + VersionRequirement: ~2.0.0 + aws.greengrass.TokenExchangeService: + VersionRequirement: ~2.0.0 +Manifests: + - Platform: + os: all + Lifecycle: + run: docker-compose -f {artifacts:path}/docker-compose.raspberrypi.yml up + Artifacts: + - URI: "docker:767397954739.dkr.ecr.eu-west-1.amazonaws.com/edge_orchestrator.raspberrypi:latest" + - URI: "docker:767397954739.dkr.ecr.eu-west-1.amazonaws.com/edge_tflite_serving.raspberrypi:latest" + - URI: "docker:767397954739.dkr.ecr.eu-west-1.amazonaws.com/edge_interface.raspberrypi:latest" + - URI: "s3://bapo-greengrass-poc/docker-compose.raspberrypi.yml" \ No newline at end of file diff --git a/deployment/hub/aws/infra-as-code/.terraform.lock.hcl b/deployment/hub/aws/infra-as-code/.terraform.lock.hcl new file mode 100644 index 00000000..f91900a6 --- /dev/null +++ b/deployment/hub/aws/infra-as-code/.terraform.lock.hcl @@ -0,0 +1,25 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.0.1" + constraints = "~> 5.0.0" + hashes = [ + "h1:SB38lIGsF3yHKujEBnTSsH4VOAskn8XZNPpuCPuhJYw=", + "zh:006daf4060087b5f0c13562beed33f524a6f9e04ebd72a782bfe60502076368f", + "zh:0f49636550aadd373c7e5c710600901c2f153ddd71b6c50482e1afdbb3f8d95d", + "zh:1999d2fad0a7a884aab0d191507cf895df0ea7201369a2ef37529f4253ce1065", + "zh:1b51774866cddca5a2da5a09a316e9ca078fc821f47611a184245ca892e9335d", + "zh:2875579acceba1403563c4281c76a3a9b53b970ed6494e5370e27efb6430bb50", + "zh:349eb9ab7c026b72154ce55c7bf9a69ebb3c3a4745ecfdb0c593400762ed1b0c", + "zh:38f96c14db5b3beb80748010c0a97dd097a303b24c8478a1286ce1f48a1a0375", + "zh:3d212e6e4fc54584e47faeccf501e5a68266c7fe9e36d89ad787c2e1f0e86197", + "zh:3ea61ab960ef34ff66457319b9083c8645a9f801f7b5578e7e3f616e26945f90", + "zh:584db6d88a07cac639f746104ccd5ed5c517ed99f892a143dad3bb64023098fc", + "zh:653def88ffa17b628459f942e743d30ab9fc2194af464d88258a784d9282f9f9", + "zh:9737008fea7ffbf5782fceb0108a283e91992c47bfcb93ec55ef43deaa7e509d", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:ce3ba0cabc1704c584cc46bf1432b14ba1d34b1a30e03a5694b5940cf1673ab8", + "zh:de3e6d4e1defc6032359fc229000a1458d777adb07974293f194dde069adcc04", + ] +} diff --git a/deployment/hub/aws/infra-as-code/iot.tf b/deployment/hub/aws/infra-as-code/iot.tf new file mode 100644 index 00000000..a66ffaef --- /dev/null +++ b/deployment/hub/aws/infra-as-code/iot.tf @@ -0,0 +1,24 @@ +resource "aws_iot_thing_group" "bapo-group" { + name = "bapo-group" + + properties { + description = "Bapo's thing group" + } + + tags = { + terraform = "true" + context = "poc-greengrass-by-bapo" + } +} + +resource "aws_iot_thing" "bapo-raspberry" { + name = "bapo-raspberry" + thing_type_name = "edge-device" +} + +resource "aws_iot_thing_group_membership" "bapo-thing-group" { + thing_name = "bapo-raspberry" + thing_group_name = "bapo-group" + + override_dynamic_group = true +} \ No newline at end of file diff --git a/deployment/hub/aws/infra-as-code/main.tf b/deployment/hub/aws/infra-as-code/main.tf new file mode 100644 index 00000000..27319318 --- /dev/null +++ b/deployment/hub/aws/infra-as-code/main.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0.0" + } + } + required_version = ">= 1.8.0" +} + +provider "aws" { + region = "eu-west-1" +} diff --git a/deployment/hub/aws/.gitkeep b/workstation-setup similarity index 100% rename from deployment/hub/aws/.gitkeep rename to workstation-setup