image.png
背景:基于 CentOS 7 系统的 Airflow 调度平台,部署一个定时任务,每天需要向 Windows 共享文件夹中生成 Excel 数据文件。Windows 共享文件夹地址为 \\share-fold\\data,可通过 ping 获取到其对应 IP 为 1.1.1.1,当前用户在 Winows 资源管理可直接打开该共享文件夹。

如果我们是在 Windows 系统上部署定时任务,在 Python 脚本中可以使用 os.system("net use \\1.1.1.1\\data"),然后通过 shutil.copy 的方式将本地文件复制到共享文件夹中。由于 Windows 自带的调度系统并不好用,也无法搭建 Airflow 平台,所以很多自动化任务都是借助于 Linux 下 Airflow 进行调度的。但 Linux 下如何操作 Windows 共享文件夹,本篇文章做一个系统介绍。

1. Linux操作WINs共享文件夹原理

Linux 文件系统下并不会有 Windows 共享文件夹,也无法通过 Terminal 进入,且 Linux 系统的账号和 Windows 系统的账号是独立的,也就是说 Windows 账号具备访问共享的权限,但不意味着 Linux 用户(相同账户名)就可以直接访问。

实现 Linux 用户操作 Windows 共享文件夹的方法:通过挂载的方式,将 Windows 共享文件夹作为磁盘,挂载到 Linux 指定目录下,然后 Linux 端在指定目录下操作都会同步到 Windows 共享文件夹中,比如创建一个新的文件。

2. 必须条件

首先需要确保在 Windows 端权限问题:

  • 所使用的账户可以在资源管理器中输入共享地址可以正常打开,即具备访问权限
  • 所使用的账户在该共享文件夹中可以可以创建、删除、移动文件

其次,我们来看 CentOS 端所需要具备的条件:

  • CentOS 的系统版本至少为 7 以上(实测 CentOS 6 及 6 以下的系统版本,某些共享文件夹始终无法挂载上,且没有任何办法解决该问题)
  • CentOS 用户具备 sudo 权限,因为 mount 命令只能在具备 root 权限用户使用。
  • 确保 CentOS 下存在指定挂载的文件夹,如果 CentOS 下指定路径不存在,挂载命令并不会帮你创建文件夹。
  • 已经安装 cifs-utils 组件,未安装的话,挂载命令之后会提示写保护(write-protected)提示,即无法向文件夹中写入文件。如未安装,请终端下执行下面代码
    1. $ sudo yum install cifs-utils -y

    2. 挂载Windows共享

    使用 mount 命令来挂载共享文件夹,其中 //1.1.1.1/data 为共享文件夹的地址,/home/yumingmin/data 为 CentOS 下的目录,如成功挂载的话,//1.1.1.1/data 将会全部显示在 /home/yumingmin/data 目录下。 ```bash $ sudo mount -t cifs //1.1.1.1/data /home/yumingmin/data -o username=yumingmin,password=yumingmin

查看一下是否挂载成功

$ mount -l //1.1.1.1/data on /home/yumingmin/data type cifs (rw,relatime,vers=default,cache=strict,username=yumingmin,domain=,uid=0,noforceuid,gid=0,noforcegid,addr=1.1.1.1,file_mode=0755,dir_mode=0755,soft,nounix,serverino,mapposix,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1)

  1. 正常的话,执行上述代码后,就可以看到共享已经被成功挂载了。如果出现 `host is down` 的错误,那么有可能是协议版本不匹配,可以加上 `vers=2.0` 或者 `vers=3.0` 尝试一下,但并不能保证一定可以解决问题。
  2. ```bash
  3. $ sudo mount -t cifs //1.1.1.1/data /home/yumingmin/data -o username=yumingmin,password=yumingmin,vers=2.0
  4. # 或者
  5. $ sudo mount -t cifs //1.1.1.1/data /home/yumingmin/data -o username=yumingmin,password=yumingmin,vers=3.0

值得注意的时,我们看到 mount -l 结果出现了 file_mode=0755,dir_mode=0755,显然这个只有 root 账号才有写入权限,非 root 账号并没有写入权限。

我们先尝试用非 root 账号尝试生成一个文件,显示 Permission denied 错误,权限不够。切换到 root 用户下,执行上述操作,是可以成功执行的。

  1. $ touch ~/data/402.txt
  2. touch: cannot touch ‘/home/yumingmin/data/402.txt’: Permission denied

让我们来看一下该文件夹的相关属性,其 owner 都是 root 用户,且权限为 755。

  1. $ ls -la |grep data
  2. drwxr-xr-x 2 root root 4096 Nov 5 14:33 data

这种模式下,我们唯一可做的操作:在非挂载目录下创建一个文件,然后通过 sudo 权限复制或者移动到挂载目录下,显然这不是我们想要的预期效果。

  1. $ touch ~/data2/402.txt
  2. $ sudo mv ~/data2/402.txt ~/data

2.1 失败的尝试:更改文件夹属性

既然所挂载的目录权限有问题,那我们先来更改一下文件夹的相关属性,来让非 root 用户有写入权限。

  1. # 添加写入权限
  2. $ sudo chmod -R 777 ~/data
  3. $ ls -la |grep data
  4. drwxr-xr-x 2 root root 4096 Nov 5 14:33 data
  5. # 更改文件夹 owner
  6. $ sudo chown yumingmin:yumingmin ~/data
  7. $ ls -la |grep data
  8. drwxr-xr-x 2 root root 4096 Nov 5 14:33 data

显然,我们尝试了添加写入权限和更改文件夹 owner 的方式,都没有对文件夹权限产生影响。即使是切换到 root 用户下执行,也是一样的结果。所以,此路不通。

2.2 解决方法:挂载时就添加权限

我们可以设置 dir_modefile_mode 参数,在挂载时就将权限进行设置:

  1. $ sudo mount -t cifs //1.1.1.1/data /home/yumingmin/downloads/data \
  2. -o username=yumingmin,password=yumingmin,vers=3.0,dir_mode=0777,file_mode=0777
  3. $ mount -l
  4. //1.1.1.1/data on /home/yumingmin/data type cifs (rw,relatime,vers=default,cache=strict,username=yumingmin,domain=,uid=0,noforceuid,gid=0,noforcegid,addr=1.1.1.1,file_mode=0777,dir_mode=0777,soft,nounix,serverino,mapposix,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1)
  5. $ ls -la |grep data
  6. drwxrwxrwx 2 root root 4096 Nov 5 14:33 data
  7. $ ls -la ~/data
  8. total 50108
  9. drwxrwxrwx 2 root root 4096 Nov 5 14:33 .
  10. drwxrwxr-x 4 yumingmin yumingmin 4096 Nov 5 13:25 ..
  11. -rwxrwxrwx 1 root root 778000 Jul 16 2020 401.txt

可以看到 dir_modefile_mode 参数的值都是 0777 了,且文件夹及其子文件的权限都是 777。我们重新执行下创建文件的操作,可以看到成功生成文件了,大功告成😉。

  1. $ touch ~/data/402.txt
  2. $ ls -la ~/data
  3. total 50108
  4. drwxrwxrwx 2 root root 4096 Nov 5 14:33 .
  5. drwxrwxr-x 4 yumingmin yumingmin 4096 Nov 5 13:25 ..
  6. -rwxrwxrwx 1 root root 778000 Jul 16 2020 401.txt
  7. -rwxrwxrwx 1 root root 778000 Jul 16 2020 402.txt

3. 卸载WINs共享

卸载 WINs 共享就比较简单了,使用 umount 命令来卸载共享文件夹的挂载,当然也是需要 root 权限下执行。值得注意的是,我们卸载的目录是 /home/yumingmin/data,而非 //1.1.1.1/data

  1. $ sudo umount /home/yumingmin/data

3.1 报错:target is busy

如果挂载出现 target is busy 的错误,无法卸载共享,大概率是你在挂载的共享文件夹下执行的该操作,只要退出去,再执行卸载操作即可。

3.2 报错:device is busy

如果挂载出现 device is busy 的错误,无法卸载共享,可以强制卸载:

  1. $ sudo umount -f /home/yumingmin/data

4. 参考文档