顯示具有 upgrade 標籤的文章。 顯示所有文章
顯示具有 upgrade 標籤的文章。 顯示所有文章

2024年1月1日 星期一

使用 do-release-upgrade 把 Oracle Cloud - Ubuntu 18.04 升級至 20.04 再繼續升級到 22.04

在 2019年搶了一台 Ubuntu 18.04 後,一直在那邊做例行公事。應該近一年 apt upgrade 也沒法多升級什麼就涼在那邊,趁 2024-01-01 假期,來整理一下。

升級絕對有風險,請自行評估跟承擔,在此謹流水帳紀錄,適合我的 VM 情況不代表大家都能升。

由於之前有設定防火牆來做一些簡單的防護,這次升級時要打開 1022 port 來小心一下:

$ sudo iptables -I INPUT 1 -p tcp --dport 1022 -j ACCEPT
$ sudo service netfilter-persistent save

開始操作:

$ sudo do-release-upgrade 
...
Calculating the changes

Could not calculate the upgrade

An unresolvable problem occurred while calculating the upgrade.

This was likely caused by:
* Unofficial software packages not provided by Ubuntu
Please use the tool 'ppa-purge' from the ppa-purge
package to remove software from a Launchpad PPA and
try the upgrade again.

If none of this applies, then please report this bug using the
command 'ubuntu-bug ubuntu-release-upgrader-core' in a terminal. If
you want to investigate this yourself the log files in
'/var/log/dist-upgrade' will contain details about the upgrade.
Specifically, look at 'main.log' and 'apt.log'.

接著安裝一下:

$ sudo apt-get install ppa-purge
$ sudo do-release-upgrade 
...

又碰到問題,大概看了一下 bugs.launchpad.net/ubuntu/+source/llvm-toolchain-9/+bug/1886748 ,偷懶衝:

$ sudo apt install clang-9
$ sudo do-release-upgrade 
...
Do you want to start the upgrade? 


17 packages are going to be removed. 209 new packages are going to be 
installed. 759 packages are going to be upgraded. 

You have to download a total of 886 M. This download will take about 
1 hour 52 minutes with a 1Mbit DSL connection and about 1 day 10 
hours with a 56k modem. 

Fetching and installing the upgrade can take several hours. Once the 
download has finished, the process cannot be canceled. 

 Continue [yN]  Details [d]Y

...
System upgrade is complete.

Restart required 

To finish the upgrade, a restart is required. 
If you select 'y' the system will be restarted. 

Continue [yN] Y

所幸...連得上 XD 看來完成了 Ubuntu 20.04 了

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.6 LTS
Release: 20.04
Codename: focal

繼續升上去!

$ sudo do-release-upgrade 
...
Reading cache

Checking package manager

Continue running under SSH? 

This session appears to be running under ssh. It is not recommended 
to perform a upgrade over ssh currently because in case of failure it 
is harder to recover. 

If you continue, an additional ssh daemon will be started at port 
'1022'. 
Do you want to continue? 

Continue [yN] Y

Starting additional sshd 

To make recovery in case of failure easier, an additional sshd will 
be started on port '1022'. If anything goes wrong with the running 
ssh you can still connect to the additional one. 


To continue please press [ENTER]

Do you want to start the upgrade? 


12 packages are going to be removed. 128 new packages are going to be 
installed. 826 packages are going to be upgraded. 

You have to download a total of 746 M. This download will take about 
2 minutes with your connection. 

Installing the upgrade can take several hours. Once the download has 
finished, the process cannot be canceled. 

 Continue [yN]  Details [d] Y

done
Processing triggers for dbus (1.12.20-2ubuntu4.1) ...
Processing triggers for libgdk-pixbuf-2.0-0:amd64 (2.42.8+dfsg-1ubuntu0.2) ...
Reading package lists... Done    
Building dependency tree          
Reading state information... Done

Processing snap replacements

refreshing snap lxd

refreshing snap oracle-cloud-agent

Searching for obsolete software
Reading state information... Done

Remove obsolete packages? 


127 packages are going to be removed. 

Removing the packages can take several hours. 

 Continue [yN]  Details [d]Y

...

System upgrade is complete.

Restart required 

To finish the upgrade, a restart is required. 
If you select 'y' the system will be restarted. 

Continue [yN] Y

再次登入:

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.3 LTS
Release: 22.04
Codename: jammy

2017年3月2日 星期四

[PHP] Facebook Graph API v2.2 升級提醒 - CodeIgniter 2.x 與 Facebook PHP SDK v5

這幾天一堆 fb app 被這種信轟炸:YourFBApp 的新開發人員重要通知,簡言之就是 facebook graph 舊版 api 即將在 2017/03/25 失效,請立即更新。

Facebook 開放平台變更紀錄 - https://developers.facebook.com/docs/apps/changelog

追了一下,主因是很多手上的服務是在 2014 年底開發,當時就是用 v2.2 graph api 沒錯,關鍵之處可以用搜尋:

facebook-php-sdk-v4 $ grep -r "v2.2" *
src/Facebook/FacebookRequest.php:  const GRAPH_API_VERSION = 'v2.2';


非常精準的地發現自己就是這個族群,也感謝 Facebook 賜予工作機會(誤),這樣每兩年就有新工作可以做,非常開心!接下來就是痛苦的開始,還是一口氣從 v4 升級到 v5 吧!

前提:

由於使用 PHP CodeIgniter 2.x 架構,再加上 HA 架構,因此需要處理 SESSION 的儲存機制,在此就用 DB 處理,而對 v4 SDK 中,是直接在 FacebookRedirectLoginHelper 改寫一份對於認證所需資料儲存的東西,但在 v5 架構就更漂亮了,可以把負責資料儲存的東西傳入,不需再改成 FacebookRedirectLoginHelper。若服務仍在單一機器上運行,可以略過此設計。

v4:

<?php
// FacebookRedirectLoginCIHelper
namespace Facebook;
use Facebook\FacebookRedirectLoginHelper;
class FacebookRedirectLoginCIHelper extends \Facebook\FacebookRedirectLoginHelper {
private $sessionPrefix = 'FBRLH_';
public function __construct($redirectUrl, $appId = null, $appSecret = null) {
parent::__construct($redirectUrl, $appId, $appSecret);
$this->ci = & get_instance();
}
protected function storeState($state) {
if ($this->ci->session->set_userdata($this->sessionPrefix . 'state', $state)) {
$this->state = $this->ci->session->set_userdata($this->sessionPrefix . 'state', $state);
return $this->state;
}
return NULL;
}
protected function loadState() {
return $this->state = $this->ci->session->userdata($this->sessionPrefix . 'state');
}
}

v5:

<?php
// FacebookSessionPersistentDataCIHandler
namespace Facebook\PersistentData;
use Facebook\Exceptions\FacebookSDKException;
class FacebookSessionPersistentDataCIHandler implements PersistentDataInterface {
protected $sessionPrefix = 'FBRLH_';
public function __construct($enableSessionCheck = true) {
$this->ci = & get_instance();
}
public function get($key) {
if ($this->ci)
return $this->ci->session->userdata($this->sessionPrefix . $key);
return null;
}
public function set($key, $value) {
if ($this->ci)
$this->ci->session->set_userdata($this->sessionPrefix . $key, $value);
}
}


初始化:

v4:

require 'path/facebook-php-sdk-v4/autoload.php';
use Facebook\FacebookRedirectLoginCIHelper;
use Facebook\FacebookRequest;
use Facebook\FacebookSession;
use Facebook\GraphUser;

FacebookSession::setDefaultApplication($this->config->item("api_key"), $this->config->item("secret_key"));

v5:

require 'path/php-graph-sdk-5.4.4/src/Facebook/autoload.php';
use Facebook\Facebook;
use Facebook\Authentication\AccessToken;
use Facebook\PersistentData\FacebookSessionPersistentDataCIHandler;
use Facebook\FacebookRequest;

$fb = new Facebook([
'app_id' => $this->config->item("api_key"),
'app_secret' => $this->config->item("secret_key"),
'persistent_data_handler' => new FacebookSessionPersistentDataCIHandler(),
//'default_graph_version' => 'v2.8',
]);


取得登入網址:

v4:

$helper = new FacebookRedirectLoginCIHelper($callback_url);
$login_url = $helper->getLoginUrl($this->config->item('fb_scope'));

v5:

$helper = $fb->getRedirectLoginHelper();
$login_url = $helper->getLoginUrl($callback_url, $this->config->item('fb_scope'));


登入完成取得 access_token:

v4:

$fb_session = $helper->getSessionFromRedirect();
$access_token = $fb_session->getAccessToken();

v5:

$accessToken = $helper->getAccessToken();


取得 longlived access_token:

v4:

$long_lived_token = $fb_session->getLongLivedSession()->getToken();

v5:
$long_lived_token = (string) $fb->getOAuth2Client()->getLongLivedAccessToken($access_token);


查詢個人資料:

v4:

$user_profile = (new FacebookRequest($fb_session, 'GET', '/me'))->execute()->getGraphObject(GraphUser::className());
$uid = $user_profile->getProperty('id');
$name = $user_profile->getProperty('name');
$email = $user_profile->getProperty('email');
$profile_url = $user_profile->getProperty('link');
if (empty($profile_url))
$profile_url = https://www.facebook.com/$uid";
$profile_image_link = "https://graph.facebook.com/$uid/picture";

v5:

$user_profile = $fb->get('/me', $accessToken)->getGraphNode();
$uid = $user_profile->getField('id');
$name = $user_profile->getField('name');
$email = $user_profile->getField('email');
$profile_url = $user_profile->getField('link');
if (empty($profile_url))
$profile_url = https://www.facebook.com/$uid";
$profile_image_link = "https://graph.facebook.com/$uid/picture";


從字串初始化並檢查 token 是否過期:

v4:

use Facebook\FacebookSession;

$session = new FacebookSession( $token );
return $session->validate();

v5:

return $fb->getOAuth2Client()->debugToken( $token )->getIsValid() == true;


api 查詢架構:

v4:

function query($token, $method, $api, $array_mode = true) {
if (!empty($token)) {
$session = new FacebookSession($token);
                 if (!$session->validate())
return false;
$response = ( new FacebookRequest( $session, $method, $api ) )->execute();
if ($array_mode)
return $response->getGraphObject()->asArray();
return $response->getGraphObject();
}
return false;
}

v5:

function _node_query($token, $method, $api, $array_mode = true) {
if (!empty($token)) {
try {
if (!strcasecmp($method, 'POST'))
return $array_mode ? $this->fb->post($api, $token)->getGraphNode()->asArray() : $this->fb->post($api, $token)->getGraphNode();

return $array_mode ? $this->fb->get($api, $token)->getGraphNode()->asArray() : $this->fb->get($api, $token)->getGraphNode();
} catch (Exception $e) {
var_dump($e);
}
}
return false;
}

function _edge_query($token, $method, $api, $array_mode = false) {
if (!empty($token)) {
try {
if (!strcasecmp($method, 'POST'))
return $array_mode ? $this->fb->post($api, $token)->getGraphEdge()->asArray() : $this->fb->post($api, $token)->getGraphEdge();

return $array_mode ? $this->fb->get($api, $token)->getGraphEdge()->asArray() : $this->fb->get($api, $token)->getGraphEdge();
} catch (Exception $e) {
var_dump($e);
}
}
return false;
}


取得使用者權限清單:

v4:

query($token, 'GET', '/me/permissions');

v5:

_edge_query($token, 'GET', '/me/permissions');


查詢朋友清單:

v4:

function get_friend_installed_app_list($token, &$have_next_page, $page = 1, $item_per_page = 25) {
$have_next_page = false;
$data = $this->query($token, 'GET', '/me/friends?fields=installed&limit='.($item_per_page).'&offset='.(($page - 1) * $item_per_page));
if(isset($data['data']) && ($cnt = count($data['data'])) > 0) {
if (isset($data['paging']) && is_object($data['paging']) && property_exists($data['paging'], 'next')) {
if ($cnt >= $item_per_page)
$have_next_page = true;
}
$output = array();
foreach($data['data'] as $user)
if (is_object($user) && property_exists($user, 'id'))
array_push($output, $user->id);
return $output;
}
return false;

}

v5:

function get_friend_installed_app_list($token, &$have_next_page, $page = 1, $item_per_page = 25) {
$have_next_page = false;
$data = $this->_edge_query($token, 'GET', '/me/friends?fields=installed&limit='.($item_per_page).'&offset='.(($page - 1) * $item_per_page), false);
$items = $data->asArray();
if(is_array($items) && ($cnt = count($items)) > 0) {
$paging = $data->getMetaData();
if (isset($paging['paging']) && isset($paging['paging']['next']))
if ($cnt >= $item_per_page)
$have_next_page = true;
$output = array();
foreach($items as $user)
if (isset($user['id']))
array_push($output, $user['id']);
return $output;
}
return false;
}


收工!

2014年9月19日 星期五

[OSX] 使用 App Store 更新 Xcode 發生錯誤 @ Mac OS X 10.9.5, MBA


主因也有可能是空間太少了 :P
除了準備空間外,可以試看看 App Store Debug 界面:

$ defaults write com.apple.appstore ShowDebugMenu -bool true

接著重新打開 App Store 後,上方最右邊有 Debug 選項 -> Reset Application,大概多做幾次即可。如果很不幸的一直不幸,最終解法就是反安裝後,再下載。

2014年5月15日 星期四

Linode - Free Upgrade、Restore from Backup、Resize 的時間花費

說真的 Linode 提供的服務對個人而言還滿好用的,只是對於公司營運 service 的不中斷的需求來說,則沒有 AWS 好用 Orz 雖然 Linode 也有 Node Balancer 可以用,但絕大部分的 High Availability 都仍透過 WebOps 負責處理,耗掉的人力並不低,而花在 AWS 的錢,其實就跟請 2~3 位 WebOps 的錢沒兩樣時,但底下的 WebOps 人力可以精簡又做得快樂時,何樂不為?

回到主題,這邊主要是趁 Free Upgrade 模式以及 Backup (Restore to) 機制,測試開一台機器所要耗費的時間,對 Linode 而言,原理都是把機器的硬碟資料 snapshot 起來,再搬到到另一台機器,啟動。所以最耗時的地方都落在資料搬移(複製)。



至於耗時為何需要在意?實在是使用 Linode 等 VPS 後,深深體會不能把這些機器都當做不會掛,某一派 SA 會覺得終於不用管"硬體"了,但這幾個月體驗了數次 Linode Hardware Issue 而直接強迫中斷服務,實在有夠痛 XD 雖然不用自己去修硬體,但服務中斷等同 WebOps 進入加班啊,因此,耗時對初期沒做 HA 的架構來說,就是代表要花多久解決中斷的服務,這時通常是透過 Backups 的 "Restore to" 。

此例分別以 Linode HDD Size 為例:
  • 48GB: 約 16 分鐘
  • 96GB: 約 23 分鐘
  • 384GB: 約 97 分鐘

2014年5月6日 星期二

[Linux] 從 Ubuntu 12.04 / MySQL 5.5 升級到 Ubuntu 14.04 / MySQL 5.6 過程 @ Ubuntu 12.04

由於某台機器接近閒置,原本單純想把 MySQL 5.5 升級到 MySQL 5.6 的,後來看一下 Ubuntu 14.04 裡頭有 MySQL 5.6 可以用,就把它升了。

連續過程:

$ sudo do-release-upgrade -d

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04 LTS
Release:        14.04

Codename:       trusty

$ service mysql stop

$ sudo apt-get remove mysql-common mysql-server-5.5 mysql-server-core-5.5 mysql-client-5.5 mysql-client-core-5.5
$ sudo apt-get autoremove

$ sudo apt-get install mysql-server-5.6
$ mysql_upgrade -u root -p


更正規的 MySQL 更新方式是要先把 /var/lib/mysql 跟 /etc/mysql 備份起來才行動的,此處因為機器上的服務已經遷移(在其他處有備份),所以就這樣升了。