Skip to content

Commit 61331b0

Browse files
author
andrewluiqut
committed
1. add on_delete file_to_upload remove file from the upload list. 2. added filename prefix and suffic rules
1 parent 2bd6b61 commit 61331b0

File tree

5 files changed

+58
-15
lines changed

5 files changed

+58
-15
lines changed

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,10 @@ Determines whether the uploader provides a web interface (`web`) or no interface
7777
```yaml
7878
# cloud name, as appeared in the clouds.yaml file
7979
uploader.filestore.cloud: openstack
80-
# filestore path
80+
# the local filestore path where new or modified files are uploaded
8181
uploader.filestore.local: /home/qcr/Bagfiles
82-
uploader.filestore.cloud.container: Bagfiles
82+
# the target object store container, the uploader will attempt to create if it not already exists
83+
uploader.filestore.cloud.container: Shorts Bagfiles
8384
```
8485
The cloud name specified in the `clouds.yaml` should be set against `uploader.filestore.cloud`. If Nectar or another openstack compliant cloud service is used, then the `clouds.yaml` should normally use `openstack`. The name is found under `clouds` in the yaml file.
8586
```yaml
@@ -93,6 +94,15 @@ The `uploader.filestore.local` specifies the local directory where new files are
9394

9495
The `uploader.filestore.cloud.container` specifies the container name in the object store where the files are uploaded. If the container does not exist, the uploader will create it.
9596

97+
```yaml
98+
# exclude files with suffixes and prefixes
99+
uploader.ignore.suffix:
100+
- .active
101+
uploader.ignore.prefix:
102+
- '~'
103+
```
104+
The two yaml keys, `uploader.ignore.suffix` and `uploader.ignore.prefix`, specify a list of suffixes and prefixes of filenames that will be ignored. To define more than one suffix or prefix, add more lines under the key as a list.
105+
96106
```yaml
97107
uploader.web.host: 0.0.0.0
98108
uploader.web.port: 8071

config/uploader_config.yaml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,22 @@
44
uploader.mode: web # web or headless
55
# cloud name, as appeared in the clouds.yaml file
66
uploader.filestore.cloud: openstack
7-
# filestore path
8-
uploader.filestore.local: /home/qcr/Insync/Bagfiles
9-
uploader.filestore.cloud.container: Shorts Bagfiles
7+
# the local filestore path where new or modified files are uploaded
8+
uploader.filestore.local: /home/qcr/Bagfiles
9+
# the target object store container, the uploader will attempt to create if it not already exists
10+
uploader.filestore.cloud.container: Shorts Bagfiles
11+
# exclude files with suffixes and prefixes
12+
uploader.ignore.suffix:
13+
- .active
14+
uploader.ignore.prefix:
15+
- '~'
1016
# Upload delay
1117
uploader.delay: 30 # seconds
1218
uploader.error_count.max: 5
1319
# Dash Agent (uploader) setting
1420
uploader.web.host: 0.0.0.0
1521
uploader.web.port: 8071
16-
# uploader.web.debug.mode: False
1722
uploader.web.launch_browser: False
18-
uploader.web.auth: True # Authentication required if web mode
1923
# Main system timers for the uploader implemented by Dash
2024
uploader.system.timer: 1 # seconds
2125
uploader.console.refresh: 5 # seconds

launch/main.launch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<!-- Launch the camera monitor node first, which will launch the camera agent -->
55
<group if="$(arg run_uploader)">
66
<param name="mode" type="string" value="$(arg mode)" />
7-
<node pkg="openstack_object_uploader" type="run.py" name="openstack_object_uploader_node" output="screen" respawn="true" >
7+
<node pkg="openstack_object_uploader" type="run.py" name="openstack_object_uploader_node" output="screen" respawn="false" >
88
</node>
99
</group>
1010
</launch>

src/uploader/run.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,25 @@ def __init__(self, filestore_path):
3434
super(CustomFileSystemEventHandler, self,).__init__()
3535
self.filestore_path = filestore_path
3636
self.uploader_delay = CONFIG.get('uploader.delay', 30)
37+
# setup ignore list
38+
self.ignore_suffix = CONFIG.get('uploader.ignore.suffix', None)
39+
if self.ignore_suffix is not None and type(self.ignore_suffix) == str:
40+
self.ignore_suffix = [self.ignore_suffix]
41+
self.ignore_prefix = CONFIG.get('uploader.ignore.prefix', None)
42+
if self.ignore_prefix is not None and type(self.ignore_prefix) == str:
43+
self.ignore_prefix = [self.ignore_prefix]
44+
45+
def is_in_ignore_lists(self, filename:str) -> bool:
46+
if self.ignore_suffix is not None and type(self.ignore_suffix) in (tuple, list):
47+
for prefix in self.ignore_suffix:
48+
if filename.endswith(prefix):
49+
return True
50+
if self.ignore_prefix is not None and type(self.ignore_prefix) in (tuple, list):
51+
for prefix in self.ignore_prefix:
52+
if filename.startswith(prefix):
53+
return True
54+
return False
55+
3756
# The callback function when a create event occurs
3857
def on_created(self, event:FileSystemEvent):
3958
pass
@@ -43,10 +62,18 @@ def on_modified(self, event:FileSystemEvent):
4362
# if the event is from a modified file
4463
local_path = event.src_path
4564
filename = file_tools.get_filename(local_path)
65+
if self.is_in_ignore_lists(filename):
66+
return
4667
parent_path = file_tools.get_parent(local_path)
4768
sub_path = parent_path[len(self.filestore_path) + 1:] # the sub_path cannot start with '/' for os.path.join to work
4869
remote_filename = os.path.join(sub_path, filename)
4970
DAO.add_upload_file(local_path, filename, remote_filename, int(time.time()) + CONFIG.get('uploader.delay', self.uploader_delay))
71+
# the callback function when a file is deleted
72+
def on_deleted(self, event:FileSystemEvent):
73+
if not event.is_directory:
74+
# if the event is from a file
75+
local_path = event.src_path
76+
DAO.remove_upload_file(local_path)
5077

5178
class OpenstackObjectUploader(object):
5279
def __init__(self):
@@ -63,6 +90,7 @@ def __init__(self):
6390
try:
6491
self.cloud = openstack.connect(cloud=self.cloud_name)
6592
except openstack.exceptions.ConfigException as e:
93+
self.cloud = None
6694
logger.error(f'{type(self).__name__}: The application is unable to locate the application credential file "clouds.yaml".')
6795
logger.warning(f'{type(self).__name__}: Ensure that a clouds.yaml file is obtained from the openstack cloud provider.')
6896
logger.warning(f'{type(self).__name__}: If you have a valid clouds.yaml file, make sure it is in the current directory or ~/.config/openstack and only one cloud.yaml file.')
@@ -93,14 +121,15 @@ def __init__(self):
93121
sys.exit(1)
94122
# attempt to make a connection to the container
95123
try:
96-
self.container = self.cloud.object_store.create_container(self.filestore_container, is_content_type_detected=True)
97-
logger.info(f'{type(self).__name__}: Connected to (and if needed created) the container "{self.filestore_container}"')
124+
if self.cloud is not None:
125+
self.container = self.cloud.object_store.create_container(self.filestore_container, is_content_type_detected=True)
126+
logger.info(f'{type(self).__name__}: Connected to (and if needed created) the container "{self.filestore_container}"')
98127
except keystoneauth1.exceptions.http.Unauthorized as e:
99128
logger.error(f'{type(self).__name__}: The application is unable to authenticate using the credentials in "clouds.yaml".')
100129
logger.warning(f'{type(self).__name__}: Ensure that the file is current and valid to the cloud server.')
101130
logger.warning(f'{type(self).__name__}: The access right should include granting access to an object store.')
102131
logger.warning(f'{type(self).__name__}: Terminate the application and fix the problem according to the README.md file.')
103-
sys.exit(1)
132+
sys.exit(1)
104133

105134
# start the watchdog
106135
self.watchdog_thread = self.run_watchdog(self.filestore_local)
@@ -174,14 +203,14 @@ def run_uploader(self):
174203
if len(next_to_upload) == 0:
175204
continue
176205
# starts the uploading procedure
177-
model.STATE.update(model.SystemStates.UPLOADING)
178206
# compute the parameters for uploading including the local and remote path
179207
model.STATE.set_var('upload', next_to_upload[0])
180208
local_path = next_to_upload[0]['local_path']
181209
remote_path = next_to_upload[0]['remote_path']
182210
file_size = (os.stat(local_path).st_size)
183211
start_time = time.time()
184212
logger.info(f'{type(self).__name__} (run_uploader): Uploading file {local_path} to {remote_path}')
213+
model.STATE.update(model.SystemStates.UPLOADING)
185214
try:
186215
self.cloud.object_store.upload_object(container=self.container, name=remote_path, filename=local_path)
187216
# compute the upload time

src/uploader/web/dashapp_top.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def _define_app(self):
6464
self._navbar_with_menu = dbc.NavbarSimple(
6565
children=[
6666
dbc.NavItem(dbc.NavLink('Console', href='/page_console')),
67-
dbc.NavItem(dbc.NavLink('DB', href='/page_db_browser')),
67+
# dbc.NavItem(dbc.NavLink('DB', href='/page_db_browser')),
6868
],
6969
brand=html.Div([html.H3(_APP_NAME), html.H6('Robotics and Autonomous Systems Group, REF, RI, Queensland University of Technology')]),
7070
brand_href='/page_console', color='#ffc6aa', className='fs-4 text')
@@ -108,8 +108,8 @@ def display_page(pathname):
108108
try:
109109
if pathname == '/page_console':
110110
page_content = self._console_page.layout()
111-
elif pathname == '/page_db_browser':
112-
page_content = self._db_browse_page.layout()
111+
# elif pathname == '/page_db_browser':
112+
# page_content = self._db_browse_page.layout()
113113
elif pathname == '/':
114114
page_content = self._console_page.layout()
115115
else: # if redirected to unknown link

0 commit comments

Comments
 (0)