blob: 5bae0e92d2a9ff53eb2ef26b78bcbe2bbe6a013e [file] [log] [blame]
tierno87858ca2018-10-08 16:30:15 +02001# -*- coding: utf-8 -*-
2
3# Copyright 2018 Telefonica S.A.
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
14# implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17
aticig3dd0db62022-03-04 19:35:45 +030018from http import HTTPStatus
19import logging
tierno5c012612018-04-19 16:01:59 +020020import os
aticig3dd0db62022-03-04 19:35:45 +030021from shutil import rmtree
bravof98fc8f02021-11-04 21:16:00 -030022import tarfile
23import zipfile
garciadeblas2644b762021-03-24 09:21:01 +010024
tierno3054f782018-04-25 16:59:53 +020025from osm_common.fsbase import FsBase, FsException
tierno5c012612018-04-19 16:01:59 +020026
27__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
28
29
30class FsLocal(FsBase):
garciadeblas2644b762021-03-24 09:21:01 +010031 def __init__(self, logger_name="fs", lock=False):
tierno1e9a3292018-11-05 18:18:45 +010032 super().__init__(logger_name, lock)
tierno5c012612018-04-19 16:01:59 +020033 self.path = None
34
35 def get_params(self):
36 return {"fs": "local", "path": self.path}
37
38 def fs_connect(self, config):
39 try:
40 if "logger_name" in config:
41 self.logger = logging.getLogger(config["logger_name"])
42 self.path = config["path"]
43 if not self.path.endswith("/"):
44 self.path += "/"
45 if not os.path.exists(self.path):
garciadeblas2644b762021-03-24 09:21:01 +010046 raise FsException(
47 "Invalid configuration param at '[storage]': path '{}' does not exist".format(
48 config["path"]
49 )
50 )
tierno5c012612018-04-19 16:01:59 +020051 except FsException:
52 raise
53 except Exception as e: # TODO refine
54 raise FsException(str(e))
55
56 def fs_disconnect(self):
57 pass # TODO
58
59 def mkdir(self, folder):
60 """
61 Creates a folder or parent object location
62 :param folder:
63 :return: None or raises and exception
64 """
65 try:
66 os.mkdir(self.path + folder)
tiernoc7ac30d2019-01-25 08:56:17 +000067 except FileExistsError: # make it idempotent
68 pass
tierno5c012612018-04-19 16:01:59 +020069 except Exception as e:
70 raise FsException(str(e), http_code=HTTPStatus.INTERNAL_SERVER_ERROR)
71
tiernod4378aa2018-12-04 15:37:23 +000072 def dir_rename(self, src, dst):
73 """
74 Rename one directory name. If dst exist, it replaces (deletes) existing directory
75 :param src: source directory
76 :param dst: destination directory
77 :return: None or raises and exception
78 """
79 try:
80 if os.path.exists(self.path + dst):
81 rmtree(self.path + dst)
82
83 os.rename(self.path + src, self.path + dst)
84
85 except Exception as e:
86 raise FsException(str(e), http_code=HTTPStatus.INTERNAL_SERVER_ERROR)
87
tierno5c012612018-04-19 16:01:59 +020088 def file_exists(self, storage, mode=None):
89 """
90 Indicates if "storage" file exist
91 :param storage: can be a str or a str list
92 :param mode: can be 'file' exist as a regular file; 'dir' exists as a directory or; 'None' just exists
93 :return: True, False
94 """
95 if isinstance(storage, str):
96 f = storage
97 else:
98 f = "/".join(storage)
99 if os.path.exists(self.path + f):
tiernoe458cd82020-02-12 10:46:51 +0000100 if not mode:
101 return True
tierno5c012612018-04-19 16:01:59 +0200102 if mode == "file" and os.path.isfile(self.path + f):
103 return True
104 if mode == "dir" and os.path.isdir(self.path + f):
105 return True
106 return False
107
108 def file_size(self, storage):
109 """
110 return file size
111 :param storage: can be a str or a str list
112 :return: file size
113 """
114 if isinstance(storage, str):
115 f = storage
116 else:
117 f = "/".join(storage)
118 return os.path.getsize(self.path + f)
119
bravof98fc8f02021-11-04 21:16:00 -0300120 def file_extract(self, compressed_object, path):
tierno5c012612018-04-19 16:01:59 +0200121 """
122 extract a tar file
bravof98fc8f02021-11-04 21:16:00 -0300123 :param compressed_object: object of type tar or zip
tierno5c012612018-04-19 16:01:59 +0200124 :param path: can be a str or a str list, or a tar object where to extract the tar_object
125 :return: None
126 """
127 if isinstance(path, str):
128 f = self.path + path
129 else:
130 f = self.path + "/".join(path)
bravof98fc8f02021-11-04 21:16:00 -0300131
132 if type(compressed_object) is tarfile.TarFile:
133 compressed_object.extractall(path=f)
134 elif (
135 type(compressed_object) is zipfile.ZipFile
136 ): # Just a check to know if this works with both tar and zip
137 compressed_object.extractall(path=f)
tierno5c012612018-04-19 16:01:59 +0200138
139 def file_open(self, storage, mode):
140 """
141 Open a file
142 :param storage: can be a str or list of str
143 :param mode: file mode
144 :return: file object
145 """
146 try:
147 if isinstance(storage, str):
148 f = storage
149 else:
150 f = "/".join(storage)
151 return open(self.path + f, mode)
152 except FileNotFoundError:
garciadeblas2644b762021-03-24 09:21:01 +0100153 raise FsException(
154 "File {} does not exist".format(f), http_code=HTTPStatus.NOT_FOUND
155 )
tierno5c012612018-04-19 16:01:59 +0200156 except IOError:
garciadeblas2644b762021-03-24 09:21:01 +0100157 raise FsException(
158 "File {} cannot be opened".format(f), http_code=HTTPStatus.BAD_REQUEST
159 )
tierno5c012612018-04-19 16:01:59 +0200160
161 def dir_ls(self, storage):
162 """
163 return folder content
164 :param storage: can be a str or list of str
165 :return: folder content
166 """
167 try:
168 if isinstance(storage, str):
169 f = storage
170 else:
171 f = "/".join(storage)
172 return os.listdir(self.path + f)
173 except NotADirectoryError:
garciadeblas2644b762021-03-24 09:21:01 +0100174 raise FsException(
175 "File {} does not exist".format(f), http_code=HTTPStatus.NOT_FOUND
176 )
tierno5c012612018-04-19 16:01:59 +0200177 except IOError:
garciadeblas2644b762021-03-24 09:21:01 +0100178 raise FsException(
179 "File {} cannot be opened".format(f), http_code=HTTPStatus.BAD_REQUEST
180 )
tierno5c012612018-04-19 16:01:59 +0200181
182 def file_delete(self, storage, ignore_non_exist=False):
183 """
tiernod4378aa2018-12-04 15:37:23 +0000184 Delete storage content recursively
tierno5c012612018-04-19 16:01:59 +0200185 :param storage: can be a str or list of str
186 :param ignore_non_exist: not raise exception if storage does not exist
187 :return: None
188 """
tiernoc7ac30d2019-01-25 08:56:17 +0000189 try:
190 if isinstance(storage, str):
191 f = self.path + storage
192 else:
193 f = self.path + "/".join(storage)
194 if os.path.exists(f):
195 rmtree(f)
196 elif not ignore_non_exist:
garciadeblas2644b762021-03-24 09:21:01 +0100197 raise FsException(
198 "File {} does not exist".format(storage),
199 http_code=HTTPStatus.NOT_FOUND,
200 )
tiernoc7ac30d2019-01-25 08:56:17 +0000201 except (IOError, PermissionError) as e:
garciadeblas2644b762021-03-24 09:21:01 +0100202 raise FsException(
203 "File {} cannot be deleted: {}".format(f, e),
204 http_code=HTTPStatus.INTERNAL_SERVER_ERROR,
205 )
David Garcia788b9d62020-01-20 13:21:06 +0100206
tiernob07e4ef2020-05-06 14:22:48 +0000207 def sync(self, from_path=None):
David Garcia788b9d62020-01-20 13:21:06 +0100208 pass # Not needed in fslocal
lloretgallegf296d2a2020-09-02 09:36:24 +0000209
210 def reverse_sync(self, from_path):
211 pass # Not needed in fslocal