威联通折腾篇十四:迁移系统盘

当时安装系统的时候就直接插入了一块硬盘,安装在了第一块机械硬盘上面,虽然读写也没有遇到什么瓶颈,但是记录以做备份,可以用于将系统迁移到 SSD 上。

下面的方法未经验证,慎用。应用可以迁移,但是一些配置可能无法成功备份到另一块硬盘中。

  1. Create a small new Volume using some of the unused space in Storage Pool 1
  2. Back up my System Setting (ControlPanel>Backup/Restore>Back up System Settings)
  3. Shut down NAS (systems that access the iSCSI storage will also be shut down)
  4. Pull the 1TB drive (System Volume)
  5. Put a 2 TB drive in both bay 3 and 4 (matching the model in bay 1 and 2)
  6. Power the NAS back on
  7. Restore from the backup taken in step 2 (point to the new volume created in step 1 for the System Volume)
  8. Add the new disks to the RAID Group in Storage Pool 1 and Migrate to RAID 5 then 6.

我把我的 NAS 系统盘搞砸了

2020 年 1 月 10 号更新。

qnap dashboard disk failed

我的 NAS 没有组 RAID,因为磁盘也不是一次买的,所以是一次次增加到 NAS 中的,每块磁盘都是独立的 Volumn,在这种情况下系统盘损坏也就无法从其他盘恢复了。

qnap storage snapshots

上面的方法在硬盘还能正常运行的时候可以试试,但是从昨天起发现 NAS 系统盘突然只读,而无法写入,经过一系列诊断初步感觉是硬盘故障了,所以赶紧备份系统盘数据,也幸亏 NAS 在要磁盘完全挂之前还保存了读的功能,所以赶紧 ssh 到后台 rsync 系统盘数据到其他盘。

qnap disk health check

备份完普通文件剩下的配置和应用就比较难备份了,前前后后花了很长时间去尝试和配置这些应用,但是最糟糕的可能就是要从头开始了。这么多应用和配置都要从头配置,想想就头疼。

qnap all applications

在网上经过一番调查,QNAP QTS 系统和数据是分开存储的,所以即使系统盘挂掉,其他磁盘不用其他操作,可以更换新的系统盘,然后安装新系统,然后在新系统中恢复原来的数据。

先在”存储与快照总管”,安全卸载存储区。所有的盘都卸载掉,然后关机。换一个用来安装系统和应用的硬盘,重装系统。装好之后插上旧数据硬盘。在存储与快照总管那里,扫描闲置磁盘。然后原来的数据就恢复了。

安全卸载磁盘:

  • 主菜单,存储与快照总管,存储,存储 / 快照
  • 选择存储池
  • 管理,打开存储池管理窗口
  • 删除 > 安全卸载存储池 (注意这里千万要选择卸载存储池,而不是移除存储池)
  • 单击“是”,存储池状态更改为安全卸载中…。QTS 卸载完存储池后,将从存储与快照总管中消失。
  • 从 NAS 中移除包含存储池的硬盘

恢复磁盘:

  • 在第二个 NAS 上安装硬盘。
  • 在第二个 NAS 上,转到主菜单 > 存储与快照总管 > 存储 > 磁盘 /VJBOD
  • 选择恢复 > 扫描闲置磁盘。 此时会出现确认消息。 单击确定。
  • QTS 将扫描磁盘并检测存储池。
  • 单击应用。

该方法也适用于将存储池移动到其他 NAS 中。1

storage pool

对于我这种只用了一块磁盘一个静态卷来安装系统的,恢复起来就比较麻烦了,大思路就是:

  • 通过 QTS 自带的备份来备份系统设置
  • 备份该盘中所有数据
  • 备份 /share/CACHEDEV1_DATA/.qpkg/ 目录下应用数据及配置
  • 再将其他数据磁盘数据卷通过上面的方法移除,然后关机,再将系统磁盘移除
  • 然后插入新的磁盘,在新磁盘上新建卷,安装系统
  • 在新系统中恢复之前备份的设置
  • 重新安装应用,然后从备份中恢复之前备份的应用数据

reference


2019-07-18 qnap , backup , system , nas

Intellij IDEA 支持 jQuery

在 设置中进行如下操作开启 jQuery 支持:

  • First press CTRL + ALT + S and go to settings.
  • Then click from the menu Languages & Frameworks
  • Select Javascript from the section below and select Libraries
  • In the open menu on the right, click on the Download button and select JQuery from the list
  • Download it and apply. It is done.

reference


2019-07-14 intellij , intellij-idea , javascript , jquery

使用 Tampermonkey 调试本地脚本

记录一下使用 Tampermonkey 调试本地脚本。

Tampermonkey 加载开发调试本地 js

首先设置 Tampermonkey 插件的设置

  • Chrome 中打开 chrome://extensions
  • 搜索 Tampermonkey ,并且在设置中开启 Allow access to file URLs

然后在文件中使用 @require 引入外部文件。

// ==UserScript==
// @name         Debug Userscript
// @namespace    https://github.com/einverne/userscripts
// @version      0.1
// @description  This is a debug script to load userscripts from local file system. NOTICE, you need to turn on Allow access to file URLs to @require local file https://www.tampermonkey.net/documentation.php
// @author       Ein Verne
// @match        http*://*
// @include      http://*
// @include      https://*
// @include      *
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @grant        GM_getResourceText
// @require      https://unpkg.com/dexie@latest/dist/dexie.js
// @require      file:///home/einverne/Git/userscripts/douban_export/douban_exporter.user.js
// ==/UserScript==

(function () {
    'use strict';

    console.log("debug script start here");
    // Your code here...
})();

reference


2019-07-13 tampermonkey , userscripts , userscript

Linux 下设置编码格式 locales

很多人在程序中会处理 non-ASCII 字符,在日志中,在终端显示中等等。

locales installs

检查 locales 是否安装

dpkg -l locales

如果 locales 之前显示 ii 表示已经安装了,否则

sudo apt install locales

重新配置

dpkg-reconfigure locales

locales 配置

使用命令 locale 查看配置

locale
LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_CTYPE=en_US.UTF-8
LC_NUMERIC=zh_CN.UTF-8
LC_TIME=zh_CN.UTF-8
LC_COLLATE="en_US.UTF-8"
LC_MONETARY=zh_CN.UTF-8
LC_MESSAGES="en_US.UTF-8"
LC_PAPER=zh_CN.UTF-8
LC_NAME=zh_CN.UTF-8
LC_ADDRESS=zh_CN.UTF-8
LC_TELEPHONE=zh_CN.UTF-8
LC_MEASUREMENT=zh_CN.UTF-8
LC_IDENTIFICATION=zh_CN.UTF-8
LC_ALL=

.bashrc 中放入如下设置:

export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

Q & A

某些情况下在终端 less /path/to/logfile 会显示 \u 开头的中文编码,这是 unicode 编码,大部分情况下 less 会使用 UTF-8 去查看文件。但是如果文件编码格式非 UTF-8 那么可能会有些问题。

使用 file /path/to/file 来查看文件的编码。

reference


2019-07-12 locale , unix , linux , encoding , utf8

jbpm 流程

BPMN 中可执行的工作流包含一系列不同类型的节点,这些节点可以被用来连接生成有序的工作流。BPMN 2.0 规范定义了三种主要的类型:

  • Events, 用来定义特定事件的发生。可以是起始事件(用来表示工作流的开始),结束事件(用来表示工作流的结束,或者子流程结束),中间事件(表示发生在工作流执行过程中的事件)
  • Avtivities, 定义了在工作流执行过程中需要执行的不同动作。依据不同类型的内容,存在不同类型的 tasks,并且 activities 可以被嵌套
  • Gateways, 用来定义不同路径,根据不同类型的 Gateway,这可能是 parallel.

jBPM6 并没有实现 BPMN 2.0 规范中的所有元素和属性,但是提供了大部分重要的子集。

节点

Events

  • Start Event (None, Conditional, Signal, Message, Timer)
  • End Event (None, Terminate, Error, Escalation, Signal, Message, Compensation)
  • Intermediate Catch Event (Signal, Timer, Conditional, Message)
  • Intermediate Throw Event (None, Signal, Escalation, Message, Compensation)
  • Non-interrupting Boundary Event (Escalation, Signal, Timer, Conditional, Message)
  • Interrupting Boundary Event (Escalation, Error, Signal, Timer, Conditional, Message, Compensation)

Activities

  • Script Task
  • Task
  • Service Task
  • User Task
  • Business Rule Task
  • Manual Task
  • Send Task
  • Receive Task
  • Reusable Sub-Process (Call Activity)
  • Embedded Sub-Process
  • Event Sub-Process
  • Ad-Hoc Sub-Process
  • Data-Object

Gateways

  • Exclusive
  • Inclusive
  • Parallel
  • Event-Based

本文主要内容总结自 jboss jbpm 官方文档的第 8 章内容。

reference


2019-07-12 jbpm , business-process-model

Linux Mint 连接 802.1x EAP wifi network

Linux Mint 在连接 802.1x EAP 网络时,一直无法弹出用户名密码弹窗,导致一直无法连接这些网络。今天查了一下,需要手动进行连接。

打开 Network Manager,选择 Connect to Hidden Network.

  • Wi-Fi security 中选择 WAP & WPA2 Enterprise
  • 在弹出的复杂的对话框中
  • Authentication 选择 Protected EAP(PEAP)
  • 然后输入 Username 和 Password ,证书可选

选择连接即可。

reference


2019-07-11 linux-mint , wifi , wifi-network , eap , wifi-authentication

一键去除网易云音乐广告

前提条件

  • Android 手机
  • root 权限
  • Root Explorer

打开目录

/data/media/0/netease/cloudmusic/

看到 AD 目录,去除写入权限即可。

Root Explorer 如果打开的是 /sdcard 下面的目录可能无法设置权限。

netease ads remove


2019-07-09 netease , music , ads

Spring 自定义 namespace and handlers

自定义 namespaces 可以让用户有一种更方便的方式来定义 Bean。

Spring 提供了一些开箱及用的方式,比如 <mvc:annotation-driven/> 可以参考这篇文章 来查看该配置的作用。

Spring 从 2.0 开始可以支持自定义扩展 XML Schema。

XML Schema-based configuration

在了解自定义 XML Schema 之前首先要熟悉一下 Spring 的 XML Schema 配置。最简单的配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- bean definitions here -->

</beans>

如果要引入 util schema 需要这样修改

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- bean definitions here -->

</beans>

扩展 XML

实现自己的 XML

  • 创建 XML Schema 文件 xsd
  • 自定义处理器,实现 NamespaceHandler 接口
  • 自定义解析器,实现 BeanDefinitionParser 接口,可多个
  • 注册到 Spring 容器中

官方文档举了一个简单的例子,比如想要在 context 中定义

<myns:dateformat id="dateFormat"
    pattern="yyyy-MM-dd HH:mm"
    lenient="true"/>

这样的代码,那么需要做下面一些事情。

定义 XML

定义如下 dateformat.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.mycompany.com/schema/myns"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:beans="http://www.springframework.org/schema/beans"
        targetNamespace="http://www.mycompany.com/schema/myns"
        elementFormDefault="qualified"
        attributeFormDefault="unqualified">

    <xsd:import namespace="http://www.springframework.org/schema/beans"/>

    <xsd:element name="dateformat">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="beans:identifiedType">
                    <xsd:attribute name="lenient" type="xsd:boolean"/>
                    <xsd:attribute name="pattern" type="xsd:string" use="required"/>
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

编写 NamespaceHandler

编写 NamespaceHandler 来处理特定 namespace 下的元素。NamespaceHandler 在这个例子中应该处理好 myns:dateformat 的解析工作。

NamespaceHandler 接口非常简单,有三个方法:

  • init() 初始化 NamespaceHandler
  • BeanDefinition parse(Element, ParserContext) 会被 Spring 在顶层元素处理时调用
  • BeanDefinitionHolder decorate(Node, BeanDefinitionHolder, ParserContext) 处理属性或者嵌套元素时使用

比如:

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

public class MyNamespaceHandler extends NamespaceHandlerSupport {

    public void init() {
        registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());
    }

}

编写 BeanDefinitionParser

BeanDefinitionParser 会被 NamespaceHandler 内部使用,当解析特定的元素时会对应不同的解析器。比如这个例子中 dateformat 使用了 SimpleDateFormatBeanDefinitionParser 。

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

import java.text.SimpleDateFormat;

public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 1

    protected Class getBeanClass(Element element) {
        return SimpleDateFormat.class; 2
    }

    protected void doParse(Element element, BeanDefinitionBuilder bean) {
        // this will never be null since the schema explicitly requires that a value be supplied
        String pattern = element.getAttribute("pattern");
        bean.addConstructorArg(pattern);

        // this however is an optional property
        String lenient = element.getAttribute("lenient");
        if (StringUtils.hasText(lenient)) {
            bean.addPropertyValue("lenient", Boolean.valueOf(lenient));
        }
    }
}

Registering the handler and the schema

所有的编程都已经结束,剩下来的就是如何让 Spring XML 感知到所做的修改,将自定义内容注册到 Spring 中。

要实现这一点,需要考虑两点

  • 注册自定义的 NamespaceHandler
  • 注册 XSD 文件

在 resources 下创建 META-INF 目录,并创建如下两个文件

  • spring.handlers 包含对应的 XML Schema URI 到 Handler 类的映射
  • spring.schemas 包含 xsd 文件路径

META-INF/spring.handlers

定义 XML Schema 到 Handler 类映射,这个例子中

http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler

META-INF/spring.schemas

定义 XML Schema 到自定义 XSD 文件映射

http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd

当做完这些后,那么上面定义的内容就和如下的定义可以实现完全相同的功能。

<bean id="dateFormat" class="java.text.SimpleDateFormat">
    <constructor-arg value="yyyy-HH-dd HH:mm"/>
    <property name="lenient" value="true"/>
</bean>

使用自定义 XML Schema

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:myns="http://www.mycompany.com/schema/myns"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd">

    <!-- as a top-level bean -->
    <myns:dateformat id="defaultDateFormat" pattern="yyyy-MM-dd HH:mm" lenient="true"/>

    <bean id="jobDetailTemplate" abstract="true">
        <property name="dateFormat">
            <!-- as an inner bean -->
            <myns:dateformat pattern="HH:mm MM-dd-yyyy"/>
        </property>
    </bean>

</beans>

代码见 https://github.com/einverne/thrift-swift-demo/tree/master/spring-mvc-demo

reference


2019-07-05 spring , java , java-web , spring-mvc

shell script idiom

Bash 命令中一些常见的习惯。

> file redirects stdout to file
1> file redirects **stdout** to file
2> file redirects **stderr** to file
&> file redirects stdout and stderr to file

/dev/null is the null device it takes any input you want and throws it away. It can be used to suppress any output.

Using 2>&1 will redirect stderr to whatever value is set to stdout (and 1>&2 will do the opposite).


2019-07-03 bash , shell , stdout , stderr , pipeline

MySQL 日期和时间函数

记住一些常用的时间操作函数能够提高 SQL 查询的效率。比如查询过去 30 天的记录,如果不清楚 DATE_SUB() 函数可能需要手动计算一下时间点再查询,但是如果知道 DATE_SUB() 函数就可以

SELECT something FROM tb_name WHERE DATE_SUB(CURDATE(), INTERVAL 30 DAY) <= daet_col;

这个 SQL 同样会查找出来当前时间点未来的记录。

获取时间

获取当前时间

mysql> SELECT NOW();
+---------------------+
| NOW()               |
+---------------------+
| 2019-07-01 09:12:46 |
+---------------------+
1 row in set (0.00 sec)

获取时间戳,同义于 NOW()

mysql> SELECT CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP;
+---------------------+---------------------+
| CURRENT_TIMESTAMP() | CURRENT_TIMESTAMP   |
+---------------------+---------------------+
| 2019-07-01 09:13:13 | 2019-07-01 09:13:13 |
+---------------------+---------------------+
1 row in set (0.00 sec)

获取 UNIX 时间戳

mysql> select UNIX_TIMESTAMP(NOW());
+-----------------------+
| UNIX_TIMESTAMP(NOW()) |
+-----------------------+
|            1562571055 |
+-----------------------+
1 row in set (0.00 sec)

获取当前的时间 CURTIME(),结果为 hh:mm:ss 格式

mysql> SELECT CURTIME();
+-----------+
| CURTIME() |
+-----------+
| 09:13:53  |
+-----------+
1 row in set (0.01 sec)

或者

mysql> SELECT CURTIME() + 0;
+---------------+
| CURTIME() + 0 |
+---------------+
|         91525 |
+---------------+
1 row in set (0.02 sec)

计算时间

如果能查得当前时间,那么通过计算函数就能够非常快速的得到,比如过去一周,过去三十天的时间戳。

时间转换

从一个时间转换成另外一种表现方式

  • 天数 <==> 日期
  • UNIX 时间戳 <==> 日期
  • 秒数 <==> 时间

TO_DAYS

传入日期,返回一个从第 0 年 ( ‘0000-00-00’) 开始到传入日期的天数

mysql> SELECT TO_DAYS('0000-01-01');
+-----------------------+
| to_days('0000-01-01') |
+-----------------------+
|                     1 |
+-----------------------+

同理还有 TO_SECONDS(expr) 方法

FROM_DAYS

给定一个天数,返回日期。

相类似的方法还有 FROM_UNIXTIME(unix_timstamp),接受一个时间戳返回日期

时间到秒

TIME_TO_SEC(time) 传入时间返回秒数

mysql> SELECT TIME_TO_SEC('22:23:00');
        -> 80580
mysql> SELECT TIME_TO_SEC('00:39:38');
        -> 2378

同理从秒数到时间 SEC_TO_TIME(seconds)

时间日期计算

给日期增加或者减少,加减运算

时间间隔

增加时间

ADDDATE(date,INTERVAL expr unit), ADDDATE(expr,days)
DATE_ADD(date,INTERVAL expr unit), DATE_SUB(date,INTERVAL expr unit)

举例

mysql> select DATE_ADD(NOW(), INTERVAL 1 DAY);
mysql> select DATE_ADD(NOW(), INTERVAL 1 HOUR);
mysql> select DATE_ADD(NOW(), INTERVAL 1 MINUTE);
mysql> select DATE_ADD(NOW(), INTERVAL 1 SECOND);
mysql> select DATE_ADD(NOW(), INTERVAL 1 MICROSECOND);
mysql> select DATE_ADD(NOW(), INTERVAL 1 WEEK);
mysql> select DATE_ADD(NOW(), INTERVAL 1 MONTH);
mysql> select DATE_ADD(NOW(), INTERVAL 1 QUARTER);
mysql> select DATE_ADD(NOW(), INTERVAL 1 YEAR);
mysql> select DATE_ADD(NOW(), INTERVAL -1 YEAR);

同理减时间

SUBDATE(date,INTERVAL expr unit), SUBDATE(expr,days)
DATE_SUB(date,INTERVAL expr unit)

reference


2019-06-30 mysql , database , sql , date , time

电子书

最近文章

  • 对象存储服务提供商提供的免费存储容量 [[对象存储]] 的英文是 Object-based Storage System,是一种将数据以对象的形式存储在分布式系统中的服务,而不是传统的文件系统或者块存储。
  • 反查一个域名的所有子域名 前段时间看到一篇文章说因为 Nginx 的一个「特性」,在直接访问 IP ,并且没有配置默认证书的情况下 Nginx 就会返回一个 SSL 证书从而倒置域名的泄露,进而泄露了网站的源 IP,使得一些扫描网站,比如 [[censys]] 可以直接查询到域名背后的网站 IP,从而导致网站即使用了 CDN 也会遭受到攻击。在这个契机下,我又开始了衍生,因为在 censys,[[fofa]],[[Shodan]] 等等网站上你只需要输入一个域名就可以获得所有这个站点相关的信息,那么有没有办法可以在只知道一个网站域名的情况下知道所有的二级域名呢。
  • 使用 Dokku 构建属于你自己的 PaaS Dokku 是一个开源的 PaaS,用户可以非常轻松地构建自己的 PaaS 云平台。
  • zlibrary 使用技巧 之前 zlibrary 的域名被取缔也曾经是一度的热门,但是 zlibrary 并没有就此消失。这篇文章就介绍几个继续使用 zlibraray 的小技巧。
  • 《日本的细节》读书笔记 怎么知道的这一本书