Ming's blog

一個軟體工程師的旅程 :)

Problem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
~$ lsb_release -a
...
Description: Ubuntu 24.04.1 LTS
...
~$ pro status
...
Subscription: Ubuntu Pro - free personal subscription
...
~$ sudo apt update
...
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
All packages are up to date.
N: Missing Signed-By in the sources.list(5) entry for 'https://esm.ubuntu.com/apps/ubuntu'
N: Missing Signed-By in the sources.list(5) entry for 'https://esm.ubuntu.com/apps/ubuntu'
N: Missing Signed-By in the sources.list(5) entry for 'https://esm.ubuntu.com/infra/ubuntu'
N: Missing Signed-By in the sources.list(5) entry for 'https://esm.ubuntu.com/infra/ubuntu'

The problem is caused by the missing “Signed-By” option in the ESM (Expanded Security Maintenance) sources.list file.

  • Signed-By (signed-by) is an option to require a repository to pass apt-secure(8) verification with a certain set of keys rather than all trusted keys apt has configured.

Solution

1
2
~$ sudo sh -c "echo \"Signed-By: /usr/share/keyrings/ubuntu-pro-esm-apps.gpg\" >> /etc/apt/sources.list.d/ubuntu-esm-apps.sources\"\""
~$ sudo sh -c "echo \"Signed-By: /usr/share/keyrings/ubuntu-pro-esm-infra.gpg\" >> /etc/apt/sources.list.d/ubuntu-esm-infra.sources\"\""

Reference

這個網站之前因為 Cloud9 賣給 Amazon 關閉免費方案後移轉到 RedHat Codenvy,Codenvy 不像是 Cloud9 在一段時間沒使用會將工作區的狀態存起來然後暫停,而是會直接刪掉整個工作區,所以整個 Hexo 的專案檔案就這樣被砍掉(還好有 2019 年初的備份)。

中間有一些文章是暫時放在 Ming’s Blog x Notion 中。

後來去讀研究所,一直沒有時間恢復,也一直想恢復,直到今天臨時想到才把網站恢復,一晃眼就是 5 年的時間過去。

比較早期放在 Google 協作平台作為圖床的圖片也已經破圖(舊的 Google 協作平台 2023 年已經強制關閉)。幸好 Googl 有把備份 Archived Classic Site 放到 Google Drive 去,當初的圖片也都還在,再找時間放到 Backblaze B2 或者 Cloudflare R2 去!

這次趁機會把 Hexo 、hexo-theme-next 升級到最新版,整個 Hexo 的工作區的檔案也上 GitHub,預計搭配 GitHub Actions 做基本的 Containerization 然後 CD 部署到自己的 Ubutnu Server。

國中開始寫 Blog 到現在,從最一開始的 WordPress 一路到 Octopress 再到 Hexo(那時後有一段時間很流行 Static Site Generators),一晃眼 10 幾年的時間,希望還有時間、熱情加減寫一些文章 :)

早上 Grafana dashboard 的 session 過期提示我重新登入

然後發現 .. 我忘記 grafana dashboard 的密碼了 Orz


我的 grafana-server 版本是:

1
2
~$ grafana-server -v
Version 6.2.5 (commit: 6082d19, branch: HEAD)

解決方法

1
2
3
~$ sudo sqlite3 /var/lib/grafana/grafana.db
~$ update user set password = '59acf18b94d7eb0694c61e60ce44c110c7a683ac6a8f09580d626f90f4a242000746579358d77dd9e570e83fa24faa88a8a6', salt = 'F3FAxVm33R' where login = 'username';
~$ .exit

這樣就可以重置 username 的 password

還蠻 .. 暴力的 XD

Reference

最近工作上需要在 Redis 上面寫 Script,Redis 從 2.6.0 版之後包了 Lua interpreter 進去開始支援用 Lua 語言寫 Script, 所以花一些時間去熟悉久仰的 Lua 語言。

筆記一下在 Ubuntu 18.04 上手 Lua 的過程。

Install

Ubuntu 18.04 可以安裝到最新的 Lua 版本是 Lua 5.3

1
2
3
4
~$ sudo apt install lua5.3
~$ lua5.3
Lua 5.3.3 Copyright (C) 1994-2016 Lua.org, PUC-Rio
>

不過要注意的是 Redis 中的 EVAL 版本是 5.1[1]

Building from the source

~$ sudo apt install libreadline-dev
~$ git clone https://github.com/lua/lua
~$ cd ./lua
~$ make all
~$ mv ./lua ./lua /usr/local/bin
~$ lua
Lua 5.4.0 Copyright (C) 1994-2019 Lua.org, PUC-Rio

Example: Hello, world!

Interactive Mode

1
2
3
4
5
6
~$ lua
lua
Lua 5.4.0 Copyright (C) 1994-2019 Lua.org, PUC-Rio
> print("Hello, world!")
Hello, world!
>

helloworld.lua

1
~$ vim helloworld.lua
1
2
3
4
5
6
function helloWorld(name)
assert(type(name) == "string", "name expects a string")
return string.format("Hello, %s!", name)
end

print(helloWorld("world"))
1
2
~$ lua helloworld.lua
Hello, world!

Unit Test

要在 Lua 寫 Unit Test 的話,根據 Unit Testing - lua-users wiki 的範例是使用 bluebird75/luaunit

安裝 luaunit module 以 Lua 5.4 為例

1
2
3
4
~$ lua -v | awk '{print $2}'
5.4.0
~$ sudo mkdir -p /usr/local/share/lua/5.4/luaunit/
~$ sudo curl -o /usr/local/share/lua/5.4/luaunit/init.lua https://raw.githubusercontent.com/bluebird75/luaunit/master/luaunit.lua

安裝 luaunit module 以 5.3 為例

1
2
3
4
lua5.3 -v | awk '{print $2}'
5.3.3
~$ sudo mkdir -p /usr/share/lua/5.3
~$ sudo curl -o /usr/share/lua/5.3/luaunit.lua https://raw.githubusercontent.com/bluebird75/luaunit/master/luaunit.lua

Example: helloWorld module

helloworld.lua

1
2
3
4
5
6
7
8
module = {}

function module.helloWorld(name)
assert(type(name) == "string", "name expects a string")
return string.format("Hello, %s!", name)
end

return module

test_helloworld.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
luaUnit = require("luaunit")
testModule = require("helloworld")

function testHelloWorld()
local ret = testModule.helloWorld("world")
luaUnit.assertEquals(type(ret), "string")
luaUnit.assertEquals(ret, "Hello, world!")

ret = testModule.helloWorld("ming")
luaUnit.assertEquals(type(ret), "string")
luaUnit.assertEquals(ret, "Hello, ming!")

ret = testModule.helloWorld(integer)
luaUnit.assertEquals(type(ret), "string")
luaUnit.assertEquals(ret, "Hello, ming!")
end

os.exit(luaUnit.LuaUnit.run())

Run LuaUnit

1
2
3
4
5
6
~$ lua test_helloworld.lua -v
Started on Mon Jul 8 15:06:09 2019
testHelloWorld ... Ok
=========================================================
Ran 1 tests in 0.000 seconds, 1 success, 0 failures
OK

Error Handling

helloworld.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module = {}

local function helloWorld(name)
-- assert(type(name) == "string", {message="name expects a string"})
if type(name) ~= "string" then
error({message="name expects a string"})
end

return string.format("Hello, %s!", name)
end

function module.HelloWorld(name)
-- Error Handling
-- Reference: https://blog.golang.org/error-handling-and-go
local success, result = pcall(helloWorld, name)
if not success then
return "", result.message
end

return result, nil
end

return module

test_helloworld.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
luaUnit = require("luaunit")
testModule = require("helloworld")

function testHelloWorld()
local ret, err = testModule.HelloWorld("world")
luaUnit.assertNil(err)
luaUnit.assertEquals(type(ret), "string")
luaUnit.assertEquals(ret, "Hello, world!")

ret, err = testModule.HelloWorld("ming")
luaUnit.assertNil(err)
luaUnit.assertEquals(type(ret), "string")
luaUnit.assertEquals(ret, "Hello, ming!")
end

function testHelloWorldWrongCase()
local ret, err = testModule.HelloWorld(123)
luaUnit.assertNotNil(err)
luaUnit.assertEquals(ret, "")
luaUnit.assertEquals(err, "name expects a string")
end

os.exit(luaUnit.LuaUnit.run())
1
2
3
4
5
6
7
~$ lua test_helloworld.lua -v
Started on Mon Jul 8 15:42:30 2019
testHelloWorld ... Ok
testHelloWorldWrongCase ... Ok
=========================================================
Ran 2 tests in 0.000 seconds, 2 successes, 0 failures
OK

Remark

  1. “EVAL is a Lua 5.1 script.” - redis.io

Reference & Resource

  • Programming in Lua
  • lua-users wiki
  • Lua Tutorial - tutorialspoint
  • Learn Lua in 15 Minutes
    Lua on Ubuntu18.04 | Ming’s blog

學習 MicroK8s (a lightweight Kubernetes distribution) 的筆記。

Read more »

1
2
3
4
5
version=$(go version)
regex="([0-9]{1,2}.[0-9]{1,2}.[0-9]{1,2})"
if [[ $version =~ $regex ]]; then
echo ${BASH_REMATCH[1]}
fi
1
2
3
4
5
6
7
8
9
10
function funcGoVersion {
version=$(go version)
regex="([0-9]{1,2}.[0-9]{1,2}.[0-9]{1,2})"
if [[ $version =~ $regex ]]; then
echo ${BASH_REMATCH[1]}
fi
}

goVersion=$(funcGoVersion)
echo $goVersion

Reference

PPTP mobtitude/vpn-pptp

1
~$ touch chapsecrets
1
2
3
# Secrets for authentication using PAP
# client server secret acceptable local IP addresses
username * password *
1
2
~$ sudo docker pull mobtitude/vpn-pptp
~$ sudo docker run --net=host --name pptp-vpn-server -d --privileged -p 1723:1723 -v /home/chapsecrets:/etc/ppp/chap-secrets mobtitude/vpn-pptp

L2TP/IPSec PSK hwdsl2/ipsec-vpn-server

1
touch vpn.env

vpn.env reference: https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/vpn.env.example

1
2
3
~$ sudo modprobe af_key
~$ sudo docker pull hwdsl2/ipsec-vpn-server
~$ sudo docker run --name ipsec-vpn-server --env-file ./vpn.env --restart=always -p 500:500/udp -p 4500:4500/udp -v /lib/modules:/lib/modules:ro -d --privileged hwdsl2/ipsec-vpn-server

Reference

1
~$ vim setup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/env python3

#from distutils.core import setup
import platform
import setuptools

def build_params():
params = {
'name':'copycat-clipboard3',
'version':'1.1',
'description':'easy way let use clip on command line with system clip (support python 3)',
'author':'Ming',
'author_email':'[email protected]',
'url':'https://github.com/iwdmb/copycat',
'py_modules':['copycat3'],
'license':'MIT',
'install_requires': ['clime', 'pyclip-copycat'],
}
if platform.system() == 'Windows':
params['scripts'] = ['copycat3.bat']
else:
params['scripts'] = ['copycat3']

return params

setuptools.setup (
**build_params()
)
1
~$ vim ~/.pypirc
1
2
3
4
5
6
7
8
[distutils]
index-servers =
pypi

[pypi]
repository=https://pypi.python.org/pypi
username=*username*
password=*password*
1
2
3
4
5
6
~$ python3 -m venv ./venv
~$ source ./venv/bin/active
~$ pip install --upgrade pip
~$ pip install --upgrade setuptools wheel
~$ python3 setup.py sdist bdist_wheel
~$ python setup.py sdist upload -r pypi

Reference

今天把系統從 Kubuntu 換成 KDE neon User Edition 並裝完 gcin 之後,發現 gcin 不能在 Konsole 中輸入中文。

解決方法很簡單也很困難,簡單之處在於安裝 gcin-qt5-immodule,難也難在安裝 gcin-qt5-immodule。

1
~$ sudo apt-get install gcin-qt5-immodule

輸入之後,會出現錯誤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
~$ sudo apt-get install gcin-qt5-immodule
Reading package lists... Done
Building dependency tree
Reading state information... Done
Starting pkgProblemResolver with broken count: 1
Starting 2 pkgProblemResolver with broken count: 1
Investigating (0) gcin-qt5-immodule [ amd64 ] < 2.8.6+eliu-0 > ( utils )
Broken gcin-qt5-immodule:amd64 Depends on qtbase-abi-5-5-1 [ amd64 ] < none -> > ( none )
Considering libqt5core5a:amd64 2904 as a solution to gcin-qt5-immodule:amd64 10000
Considering libqt5core5a:amd64 2904 as a solution to gcin-qt5-immodule:amd64 10000
Done
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
gcin-qt5-immodule : Depends: qtbase-abi-5-5-1
E: Unable to correct problems, you have held broken packages.

之前裝 LinuxMint 18 的時候有解過一次這個問題。

解決方法如下

1
2
3
sudo apt download gcin-qt5-immodule
ar x gcin-qt5-immodule_2.8.6+eliu-0_amd64.deb
vim control.tar.gz

tarfile::./control 中的 Depends

Depends: gcin-im-client (>= 2.8.6+eliu-0), libc6 (>= 2.4), libgcc1 (>= 1:3.0), libqt5core5a (>= 5.0.2), libqt5gui5 (>= 5.4.1) | libqt5gui5-gles (>= 5.4.1), qtbase-abi-5-5-1

改為:

Depends: gcin-im-client (>= 2.8.6+eliu-0), libc6 (>= 2.4), libgcc1 (>= 1:3.0), libqt5core5a (>= 5.0.2), libqt5gui5 (>= 5.4.1) | libqt5gui5-gles (>= 5.4.1)

wq 儲存

1
2
ar r gcin-qt5-immodule_2.8.6+eliu-0_amd64.deb control.tar.gz
sudo dpkg -i gcin-qt5-immodule_2.8.6+eliu-0_amd64.deb

重新執行 gcin 即可。

也可以直接下載我包好的:Download

1
2
3
4
~$ md5sum gcin-qt5-immodule_2.8.6+eliu-0_amd64.deb
55ccc5e54dad0665f81b8885c920a00d gcin-qt5-immodule_2.8.6+eliu-0_amd64.deb
~$ sha256sum gcin-qt5-immodule_2.8.6+eliu-0_amd64.deb
87c7edc510f0de68c47a9ababc16ec36c7a765a61343e474e5d6a30f6b1570a3 gcin-qt5-immodule_2.8.6+eliu-0_amd64.deb

gcin 安裝方法

1
~$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 835AB0E3
1
2
3
4
~$ deb http://hyperrate.com/gcin-ubuntu1604 eliu release
~$ deb http://hyperrate.com/gcin-ubuntu1804 eliu release
~$ deb http://hyperrate.com/gcin-ubuntu2004 eliu release
~$ deb http://hyperrate.com/gcin-ubuntu2404 eliu release
1
2
~$ sudo add-apt-repository "deb http://hyperrate.com/gcin-ubuntu2404 eliu release"
~$ sudo apt update
1
~$ im-config -n gcin
0%