Skip to content

Commit b87af81

Browse files
authored
Merge pull request #102 from BerkeleyAutomation/ICRA2023-Review
Icra2023 review to Humble Former-commit-id: 1821aa2
2 parents 87ca120 + 2dd5426 commit b87af81

File tree

12 files changed

+1019
-17
lines changed

12 files changed

+1019
-17
lines changed

Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
ARG UBUNTU_DISTRO=jammy
2-
ARG ROS_DISTRO=rolling
2+
#rolling is alternative
3+
ARG ROS_DISTRO=humble
34
FROM ubuntu:${UBUNTU_DISTRO}
45

56
# Set up install, set tzdata

fogros2/fogros2/aws_cloud_instance.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,18 @@ def __init__(
107107

108108
self.create()
109109

110+
110111
def create(self):
111112
self.logger.info(f"Creating new EC2 instance with name {self._name}")
112113
self.create_security_group()
113114
self.generate_key_pair()
114115
self.create_ec2_instance()
115116
self.info(flush_to_disk=True)
116117
self.connect()
117-
self.install_ros()
118-
self.install_colcon()
119-
self.install_cloud_dependencies()
118+
# Uncomment out the next three lines if you are not using a custom AMI
119+
#self.install_ros()
120+
#self.install_colcon()
121+
#self.install_cloud_dependencies()
120122
self.push_ros_workspace()
121123
self.info(flush_to_disk=True)
122124
self._is_created = True

fogros2/fogros2/cloud_instance.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def pip_install(self, args):
128128
self.scp.execute_cmd(f"sudo pip3 install {args}")
129129

130130
def install_cloud_dependencies(self):
131-
self.apt_install("wireguard unzip docker.io python3-pip")
131+
self.apt_install("wireguard unzip docker.io python3-pip ros-humble-rmw-cyclonedds-cpp")
132132

133133
def install_ros(self):
134134
# setup sources
@@ -159,7 +159,7 @@ def install_ros(self):
159159
self.scp.execute_cmd("export LANG=en_US.UTF-8")
160160

161161
# install ros2 packages
162-
self.apt_install(f"ros-{self.ros_distro}-desktop")
162+
# self.apt_install(f"ros-{self.ros_distro}-desktop")
163163

164164
# source environment
165165
self.scp.execute_cmd(f"source /opt/ros/{self.ros_distro}/setup.bash")
@@ -203,8 +203,10 @@ def push_ros_workspace(self):
203203
make_zip_file(workspace_path, zip_dst)
204204
self.scp.execute_cmd("echo removing old workspace")
205205
self.scp.execute_cmd("rm -rf ros_workspace.zip ros2_ws fog_ws")
206-
self.scp.send_file(f"{zip_dst}.zip", "/home/ubuntu/")
207-
self.scp.execute_cmd("unzip -q /home/ubuntu/ros_workspace.zip")
206+
#self.scp.send_file(f"{zip_dst}.zip", "/home/ubuntu/")
207+
self.scp.send_file(f"{zip_dst}.tar", "/home/ubuntu/")
208+
#self.scp.execute_cmd("unzip -q /home/ubuntu/ros_workspace.zip")
209+
self.scp.execute_cmd("tar -xf /home/ubuntu/ros_workspace.tar")
208210
self.scp.execute_cmd("echo successfully extracted new workspace")
209211

210212
def push_to_cloud_nodes(self):

fogros2/fogros2/util.py

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@
3333

3434
import errno
3535
import os
36+
from platform import architecture
3637
import shutil
38+
import tarfile
39+
3740

3841
_work_dir_cache = None
3942
_instance_dir_cache = None
@@ -70,12 +73,34 @@ def instance_dir():
7073
return _instance_dir_cache
7174

7275

73-
def make_zip_file(dir_name, target_path):
76+
# def make_zip_file(dir_name, target_path):
77+
# root_dir, workspace_name = os.path.split(dir_name)
78+
# print(root_dir, workspace_name)
79+
# return shutil.make_archive(
80+
# base_dir=workspace_name,
81+
# root_dir=root_dir,
82+
# format="zip",
83+
# base_name=target_path,
84+
# )
85+
86+
#Using Tar not Zip
87+
def make_zip_file(dir_name, target_path):
7488
root_dir, workspace_name = os.path.split(dir_name)
7589
print(root_dir, workspace_name)
76-
return shutil.make_archive(
77-
base_dir=workspace_name,
78-
root_dir=root_dir,
79-
format="zip",
80-
base_name=target_path,
81-
)
90+
base_name = os.path.abspath(target_path)
91+
os.chdir(root_dir)
92+
93+
tar_compression = ''
94+
archive_name = base_name + '.tar' + ''
95+
archive_dir = os.path.dirname(archive_name)
96+
97+
EXCLUDE_FILES = ['.git'] #https://stackoverflow.com/questions/16000794/python-tarfile-and-excludes
98+
99+
if archive_dir and not os.path.exists(archive_dir):
100+
os.makedirs(archive_dir)
101+
tar = tarfile.open(archive_name, 'w|%s' % tar_compression)
102+
try:
103+
tar.add(workspace_name, filter=lambda x: None if x.name in EXCLUDE_FILES else x)
104+
finally:
105+
tar.close()
106+
return archive_name

fogros2/fogros2/verb/image.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import boto3
2+
import os
3+
import shutil
4+
5+
from botocore.exceptions import NoRegionError
6+
from ros2cli.verb import VerbExtension
7+
8+
from ..util import instance_dir
9+
10+
11+
class ImageVerb(VerbExtension):
12+
13+
def add_arguments(self, parser, cli_name):
14+
parser.add_argument(
15+
"name",
16+
type=str,
17+
nargs="*",
18+
help="Set instance name. Can be found when running 'ros2 fog list' command next to ssh_key after "
19+
"'FogROS2KEY-'",
20+
)
21+
parser.add_argument(
22+
"--region",
23+
nargs="*",
24+
help="Set AWS region (overrides config/env settings)",
25+
)
26+
parser.add_argument(
27+
"--dry-run",
28+
action="store_true",
29+
help="Show what would happen, but do not execute",
30+
)
31+
32+
def query_region(self, region, name):
33+
try:
34+
client = boto3.client("ec2", region)
35+
except NoRegionError:
36+
raise RuntimeError(
37+
"AWS is not configured! Please run `aws configure` first."
38+
)
39+
print("Instance name: ", name)
40+
ec2_instances = client.describe_instances(
41+
Filters=[
42+
{
43+
"Name": "instance.group-name",
44+
"Values": ["FOGROS2_SECURITY_GROUP"],
45+
},
46+
{"Name": "tag:FogROS2-Name", "Values": name},
47+
]
48+
)
49+
50+
if len(ec2_instances["Reservations"]) == 0:
51+
print(
52+
"No EC2 instances found with the specified name; "
53+
"check list to be sure name is correct!"
54+
)
55+
56+
return [client, ec2_instances]
57+
58+
def create_ami(self, client, ec2_instances, dry_run):
59+
image_count = 0
60+
for res in ec2_instances["Reservations"]:
61+
for inst in res["Instances"]:
62+
tag_map = (
63+
{t["Key"]: t["Value"] for t in inst["Tags"]}
64+
if "Tags" in inst
65+
else {}
66+
)
67+
print(
68+
f"Converting {tag_map.get('FogROS2-Name', '(unknown)')} "
69+
f"{inst['InstanceId']} to AMI."
70+
)
71+
name = tag_map["FogROS2-Name"] + "-image"
72+
inst_id = inst['InstanceId']
73+
74+
if not dry_run:
75+
response = client.create_image(InstanceId=inst_id, Name=name)
76+
if response["ResponseMetadata"]["HTTPStatusCode"] != 200:
77+
raise RuntimeError(
78+
f"Could not create image for {inst['KeyName']}!"
79+
)
80+
81+
print("done.")
82+
image_count += 1
83+
84+
return image_count
85+
86+
def main(self, *, args):
87+
regions = args.region
88+
if regions is None or len(regions) == 0:
89+
regions = [None]
90+
elif "*" in regions or "all" in regions:
91+
client = boto3.client("ec2")
92+
response = client.describe_regions()
93+
regions = [r["RegionName"] for r in response["Regions"]]
94+
95+
96+
if len(regions) == 1:
97+
image_count = self.create_ami(
98+
*self.query_region(regions[0], args.name), args.dry_run
99+
)
100+
else:
101+
from concurrent.futures import ThreadPoolExecutor
102+
103+
with ThreadPoolExecutor(max_workers=len(regions)) as executor:
104+
futures = [
105+
executor.submit(self.query_region, r, args.name)
106+
for r in regions
107+
]
108+
image_count = sum(
109+
[
110+
self.create_ami(*f.result(), args.dry_run)
111+
for f in futures
112+
]
113+
)
114+
115+
if image_count == 0:
116+
print("No image was created")
117+

0 commit comments

Comments
 (0)