15 十月

Django 1.7 Migration

雖然之前就有用 South, 基本上是一樣的東西, 但是當 Django 1.7 把他納入成為 Migration 之後, 就有種扶正的感覺, 當然也開心的使用、試用。

其中一個我很喜歡的功能是 RunPython。他可以讓你執行 arbitrary code, 也許是新增一些你想要的 fixtures, 或是針對你想要的狀況作一些資料的轉換、增減等等。

不過如果你按照官方文件上面的作法, 可能有些 behavior 會跟預期的不同。例如以下的 code

def forwards_func(apps, schema_editor):
    # We get the model from the versioned app registry;
    # if we directly import it, it'll be the wrong version
    Country = apps.get_model("myapp", "Country")
    db_alias = schema_editor.connection.alias
    Country.objects.using(db_alias).bulk_create([
        Country(name="USA", code="us"),
        Country(name="France", code="fr"),
    ])

你可能會預期 Country 就是跟你現在 models.py 裡頭的 Country 一樣。但事實上, 他是依照整個 migrations 裡頭依序建構出來的 models。譬如說, 假設 0005_blablabla.py 定義了 Country, 但是上述的 procedure 是在 0004_blablabla.py, 那麼當 django 在 migrate 的時候, get_model 就會噴錯告訴你找不到 Country。

因此, dependency 要做好… (雖然 documentation 有提到, 但有時候看到 sample code 太興奮就直接用了 XD 最後 trace code 才發現是怎麼回事 orz)

另外還有一件事情就是他的 schema_editor 有提供一些 functions, 例如 alter_db_table(…) 可以把一個 table 改名字, 或是 create_model、delete_model 等, 但由於這些東西你可能會寫在 RunPython 呼叫的 function 裡頭, 導致 django migration 在 traverse 整個 migration tree 的時候無法追蹤, 因此就會造成不一致的狀況。其實目前也不知道這是該怎麼解… 所以… 就盡量避免使用吧。

21 八月

雲端平台使用心得分享

52621490_90f5660b77_z

johnmueller CC BY NC ND 2.0

好爛的標題喔 XD 小弟有幸在這兩三年使用了幾家不同的雲端平台, 想說在此分享給一些還沒有用過的朋友, 也許這些資訊有些幫助。

現在跟以前比起來, 真是一個幸福的時代。記得以前都要想辦法找一台電腦, 架個 Slackware、Redhat, 一直到大學的時候, 同學們都要把汰舊的電腦組起來裝個 FreeBSD 或什麼的來做自己的實驗機 (二號機), 裝 BBS, 裝 news server, 裝 Web server, 裝 MovableType… 裝 FTP server (orz…)

出社會後, 也曾經在自己家的客廳把舊機器組起來, 想說 VDSL 的上傳頻寬也多了, 但噪音以及熱度的問題很快的就讓我把他丟在一旁。這種東西怎麼可能會比得過按幾個紐, 就可以產生出一整台給你用的 Linux 呢? 現在的 VPS 或 IaaS 可以給的實在是多太多, 也方便太多了!

Amazon Web Service

首先, 第一個要介紹的就是最有名的 AWS。由於工作上的需要, 我們當時的整個 infrastructure 都是建立在 AWS 上的。Infrastructure 聽起來真威猛, 其實就是我們所有建構的服務 (對內、對外) 都是建立在 AWS 上的。

AWS 的 EC2 功能真的非常多, 也是當時我認為最完整的 (目前我想應該也是, 但感覺 Google Cloud Platform 緊追在後)。他們提供了一個 Free-tier 可以讓你用一整年免錢。當時 EC2 Free-tier 的機種是 t1.micro。聽起來很吸引人對吧? 但到底 t1.micro 用起來會是怎樣的呢? 簡單來說, 就是卡卡的 XD

apt-get update、apt-get upgrade 或作什麼 compiling 的動作會卡住, 在 terminal 打東西打一打也會卡住… 其實這樣的效能實用性真的不怎麼高, 所以還是使用了最便宜的付費方案 m1.small。

機房, 想當然爾的要選擇靠近台灣一點的機房, 而我們當時選擇的是東京機房。雖然很近也挺快的, 但是可以很明顯的感受到, 速度不及機器放在台灣學術網路的快。

使用 AWS 有另外一個好處, 就是可以使用 VPC (Amazon Virtual Private Cloud)。VPC 可以讓你自己設定你的虛擬網路, 不會跟別人的干擾, 可以自己設定 routing 等。如果你沒有使用 VPC 的話, 使用 EC2 的內網的網域是跟其他人共用的。但使用了 VPC, 你可以自己切 10.x.x.x 開頭的虛擬網路。如此一來, 其中一台可以架個 openvpn, 你就可以讓內部才能使用的 service 只聽 10.x.x.x 的 address 不對外公開, 也是個隔離的好辦法。

最後, EC2 有個叫做 Reserved Instance 的東西。在此要特別講一下。如果你會長時間開啟 EC2, 可以考慮購買所謂的 Reserved Instance。RI 的玩法如下: 你一開始要先繳一筆大筆的費用, 叫做 Upfront price。然後接下來的一年或三年的時間裡, 每一個月機器的價格最低可以低到原本的 25 折 (以目前 m3.small, 3-year heavy utilization RI 來算)。跟原本的方案比起來, upfront 費用加上最低 25 折的小時費率基本上還是便宜非常多。

聽起來很誘人是吧? 當你一確認使用此方案後, 你會先被扣該方案的 Upfront price, 接著, 他就會直接把當月的小時數 x 費率直接扣款, 接著使用該機型的機器使用的費用都會算成 0 元。但是有些地方要注意。首先, 你要確保你的機器真的是 24/7 都開著, 而且會開一年 (或三年)。如果公司的營運計畫有轉變, 甚至是 Amazon Web Service 推出了新的機種, 你可能就會有點後悔你跟他買了一個一年 (或三年) 約的機器了。

不過他基本上是可以賣掉的, 而且他提供了一整套的機器讓你可以線上賣出你不想要的約。然而目前只接受你有在美國的銀行開戶的戶頭才能進行這種交易。

Linode

嚴格上, 他無法跟 AWS 做比較, 因為這個純粹是 VPS, 而 AWS 應該算 IaaS。但其實他們一樣都可以拿來當作架站的底層, 因次還是合在一起講好了。選用 Linode 的好處就是他很簡單, 計價方式也很簡單, 功能也不複雜。開了一台, 選定 Linux distribution 跟一些基本設定如 swap、硬碟大小、root password, 然後開機! 你馬上就有一台全新的 Linux。

Linode 一樣最近的機房在東京。而他目前最低的費率是 USD 10/mo, 今年的新機種全面改用 SSD 硬碟。有這些改變應該是被競爭對手 DigitalOcean 追著打。不過在此沒有特別介紹 DigitalOcean 是因為之前在網路上有過一些這家供應商的爭議, 因此我就沒有使用過他們的服務了。

其實 Linode 能講的不多, 大概就是這樣子了。但使用上, 大概一兩年前使用的時候, 常常到了晚上會有點 lag, 這大概是使用上最大的麻煩吧。

對了, 另外, 在 Linode 的機器上你也可以配置 Private IP。如果你有想台 Linode 想要互連的話, 可以兩台都配置 Private IP, 就可以連線了。但這一樣要小心一點, 因為大家的帳號都是共用這個內網的。

Untitled-1

最後, Linode 的客戶服務回信的速度之快, 是非常嚇人的! 通常你發一個 ticket, 大概五到十分鐘之內就會有人回信, 我個人覺得非常威猛!

Heroku

這個就更不能跟其他比了, 但之所以會拿他出來講, 一樣, 之前曾經考慮過的省錢的 solution。他算是 PaaS, 你沒有 OS 的控制權, 而佈署網站的方式是透過 git push。

Heroku 很棒的地方在於他最低的方案是免錢的, 而大部分小網站的流量光是這個方案就可以應付了。不過他最致命的缺陷就是你可以控制得太少, 尤其是 filesystem 這一塊。我碰到的大問題就是在於, 我客戶的網站有 Content Management, 如果使用者要上傳 media, 一定要搭配 S3 之類的東西。可惜 Django 目前的 solution (django-tinymce, django-storages, django-filebrowser 三個搭配起來) 對於 S3 這種狀況會出很大的問題。每個小的 system call 都要透過 HTTP call S3 API, 很容易 timeout, 即使不 timeout 也要等非常久。

因為這樣的事情後來就放棄這個選項了。(所以這個平台我沒有真的讓 production 在上面跑過)

Google Cloud Platform

這算是目前我的新歡吧… 他最大的優勢就是在於他的機房在台灣! 在台灣!! 網路速度從台灣連非常非常的快。他的功能組比較像是 AWS, 他有內網可以建制, 然後開的機器有很多不同規格可以作選擇與調整。

然而, 目前 Google Compute Engine 提供的 OS 有限, 目前免費提供的有 Debian 7, CentOS 6, openSUSE, coreOS。我個人用 Ubuntu 用慣了, 因此在這上面選用 Debian。其實 Debian 也不錯, image 跑起來沒有亂裝一堆有的沒的, 但其實我覺得還是沒有到 Ubuntu 那麼人性化, 感覺比較 hardcore 一點。

Untitled-2

Google Compute Engine 的定價很酷, 因為當初他主打的就是他把 AWS Reserved Instance 的概念直接 Bundle 在他們所有的計價方式。因此 Google Compute Engine 你只要開機時間越久費率就越低, 不用在額外選擇年約的方案。而目前試用下來, Google Compute Engine 最低的方案 f1.micro (shared core, 0.6G RAM) 其實也不會像當初我使用 AWS t1.micro 一樣卡卡的。而這個方案組起來也是非常便宜。但最華麗的還是在於他的速度, 隨便開一台 ping 一下值可以在 8-15ms 左右, 相當驚人。

Google Compute Engine 如果你最簡單的方案開個一天兩天其實也不到一塊錢美金, 想要試用的人不妨試試看。

結語

試用了這麼多, 最後仍然要回歸到你的需求是什麼? 當初選用 AWS 是因為預計會大擴張, 因此當然是選擇這方面的領導品牌。然而, 領導品牌的價格也高出很多。如果需求轉向了, 公司所打造的服務轉向了, 那是否還需要用到這麼豪華的東西呢? 其實可能主要以成本考量, 是否在成本上也符合需求。

有些事情其實當初也真的沒有想過, 例如說使用了 RI 優惠的價格但綁約之後, 公司轉型而使用別家廠商, 又或者是雲端供應商提供了更新更好的機種… 而在選用這些服務時, 搬遷的工程, 使用 PaaS 帶來的限制導致需要更多開發或研究的工作項目, 這些增加的成本與帶來的效益是否值得呢? 但不可諱言的, 這些東西真的比以前自己動手組實體機器還要來得好多了!

17 四月

AngularJS + SVG 地雷

情況是這樣的。由於 html5mode 很漂亮, 不再有醜陋的 hash 在網址裡頭, 所以理所當然的就想辦法用這個模式。然而, IE9 並不支援 History API, 因此依照 AngularJS 的文件, 要弄個

<base href="/blabla" />

在 head 裡頭。

這都還不打緊, 但是當我想要使用 SVG 的 textPath 的時候, 他就爆炸了。textPath 是一個可以讓文字彎彎曲曲, 依照先前定義的 path 來編排的一個功能, 他的語法大致如下

<svg xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
        <path id="myTextPath" d="M75,20 a1,1 0 0,0 100,0" />
    </defs>

    <text x="10" y="100" style="stroke: #000000;">
      <textPath xlink:href="#myTextPath" >
            Text along a curved path...
      </textPath>
    </text>
</svg>

Reference: The SVG textpath element

在 <defs> 裡頭定義了一個 path, 然後接著在 textPath 裡頭會藉由 xlink:href 來指向這個 path。

此時麻煩來了, 由於 angularjs 定義了 base, 因此 xlink:href 就會自動解讀為 /blabla#myTextPath, 而造成失效 (原因是這段 svg 是動態產生的), 他確實是會想要透過網路抓取外部資料, 而我沒有任何方式可以把 base 的設定取消。

於是, 就造成了一種死結無解的狀態… orz

最後我用了爛招, 就是我把 SVG 搬移到外面, 並且給他參數讓他自動產生我想要的向量… 真的滿弱的… 只是, 這種組合又有多少人會碰到呢?

13 二月

UTF-8 正體中文 (繁體) 的筆畫排序

好像很久以前, 就已經發現到, 中文的排序是有一些問題的, 但我就放著。直到昨天在處理某個頁面時, 我發現, glossary 之類的東西, 按照筆畫排序是很重要的, 所以就 Google 了一下。

一開始, 我以為是 postgresql locale 的問題, 找到了幾個 link, 但是都沒有下文, 而且重點是我一開始在 Ubuntu 裝 postgresql 的時候, 我沒有更改設定, 所以 zh_TW 並沒有進去。開了台新機器隨便測一測, 仍然沒有達到我想要的結果。

直到我赫然發現我整個方向都錯了。後來才發現, 字元編碼本身, UTF-8 並不是按照筆畫順序排的, 但 Big5 是, 所以可以把該欄位轉成 Big5 之後再用這個欄位排序。

以下可以找到很多 MySQL 的版本:

以下是 postgresql 的 sample code。一般來說, 原本的搜尋就是像下面這樣:


db=# select id, title from kb_article order by title;
id | title
-----+------------------------------------------
158 | 丁種建築用地
80 | 不動產奢侈稅可用公告現值並扣成本嗎
78 | 不動產奢侈稅的課徵時點為何
79 | 不動產的奢侈稅稅率為何
157 | 丙種建築用地
179 | 主建物
161 | 乙種工業用地
156 | 乙種建築用地
214 | 事故屋
33 | 交屋注意事項
12 | 交易安全機制
116 | 什麼是區段化、去識別化方式提供查詢

從上面可以看到, 乙只有一劃, 但是他並沒有排在最前面。


db=# select id, title from kb_article order by convert_to(title, 'BIG5');
id | title
-----+------------------------------------------
42 | 「銷售契約」是指公契還是私契
161 | 乙種工業用地
156 | 乙種建築用地
158 | 丁種建築用地
34 | 入住前準備事宜
175 | 土地改良物
153 | 土地使用分區
152 | 土地持份
94 | 土地相關
44 | 土地重劃後之「持有期間」如何計算
191 | 大公
220 | 女兒牆
192 | 小公
79 | 不動產的奢侈稅稅率為何
80 | 不動產奢侈稅可用公告現值並扣成本嗎
78 | 不動產奢侈稅的課徵時點為何
116 | 什麼是區段化、去識別化方式提供查詢

沒想到… 這年頭… BIG5 還有這個作用 orz, 不過在 django 裡頭就只能下 raw 不能直接用他的 ORM 啦!

13 六月

Django, celery, gevent 實作 long polling

我們的一個新的網站平台, 有讓使用者上傳圖片的功能。當照片上傳過後, 我們會縮放圖片至適當的比例, 並且貼上一些浮水印之類的東西。如果我是貼上一個單眼拍下來的相片, 使用 PIL 縮圖是挺耗費時間的, 因此為了有更好的 User Experience, 我覺得這些耗費時間變成 offline 來做。然而, 我希望 server 在做完之後, browser 能夠被通知到並且將縮圖抓回來。

一開始, 我打定的主義是使用 node.js 的 socketio, 可惜我完全沒碰過 node.js, 雖然 socketio 在前後台之間的結合很完美, 但有下列問題要先解決:

  1. Ubuntu 12.04 LTS 上的 nginx 版本還沒有支援 websocket。當然也是可以更新版本。
  2. nginx 的後端有兩種 solution, django + node.js。
  3. 我要想辦法讓 django 跟 node.js 可以一起溝通, 因為網站整個都是 django, user upload 完照片後, 整個都是在 django/python 裡頭, task 的資訊要在兩邊共享

基於上述會耗費太多開發時間, 因此我多 survey 了一下, 發現 long polling 基本上就是把 request 卡住, 等到一有結果就直接回傳。用最基本的東西就可以實作。

Celery

Celery 之前就大概用過, 這一次想說直接用 SQS 作為 Message Queue, 文件上有很基本的說明, 但是有一行講得非常模糊

If you specify AWS credentials in the broker URL, then please keep in mind that the secret access key may contain unsafe characters that needs to be URL encoded.

看完沒有 sample 真的很痛苦, 因為 python urllib 的 API 文件好像找不到合用的, 一開始看大概會選擇 urllib.urlencode(query[, doseq]), 但其實這是用在 GET parameter, 會有 key 跟 value, 而 urllib.quote(string[, safe]) 用起來卻不會將 / (slash) 做 encode。搞了半天, 原來要把 safe 變成空的才 ok:

BROKER_URL = 'sqs://%s:%s@' % (AWS_ACCESS_KEY_ID, urllib.quote(AWS_SECRET_ACCESS_KEY, ''))

然而, 實作之後, 發現有不穩定的狀況, 才發現在 Brokers 的頁面上有寫著, SQS 的 status 是 experimental, 因此就火速換掉使用之前用的 rabbitMQ。(不過後來發現不穩定的狀況應該是我自己耍腦殘, 請看下面段落敘述)

gevent & long polling

查了很多 long polling, python 還有 django 的資料, 後來發現可以使用 Django+gevent 來實作。如果不使用 gevent, Django 是不太適合直接拿來做這件事情, 因為如果有多個 request 都在等待, 很快就會把 worker 全部都佔滿 (如果有錯請糾正 >”<), 而使用 gevent, 則可以使用底層的 libevent 來做多工的切換, Gevent Tutorial 的這張圖有很清楚的表達他的運作方式。因此, 如果有多個 user 在做 long polling, 也不致於會卡住。

結合在一起

接在一起的流程很簡單, 步驟如下:

  1. User 上傳檔案到後端的某隻 view。
  2. 這個 view 製作一個 celery task (apply_async), 然後將 task_id 回傳給 browser
  3. Browser 定期帶著這個 task_id 去 check 另一個叫做 poll 的 view
  4. poll 的 view 只做一件事情就是 get celery task result, 並且設定一個 timeout。所以, 只要一 timeout, browser 就會再發一次 request 卡在 poll 裡頭。

當然, 如果一次上傳多個圖片, 就可以使用 gevent 的 group, 一次開多個 greenlet 去等待, 哪一個先回傳就把整個 group 幹掉回給 browser。我寫了一個很簡單的 django-longpolling-example 放在 github, 就只是簡單的示範這個概念。

Debug 很久之自己耍笨

前天下午在睡午覺的時候, 收到 E-mail 說有使用者講無法上傳圖片, 我就跳起來 debug, 用了非長久, 發現會有漏 task 的事情發生。於是乎我 trace code trace 到了 celery、kombu、amqp 等 python library, 才發現 message 是真的都有丟出去, 但是為什麼我的 celery worker 就是會掉 task 呢? 我今天才突然驚覺, 原來我 dev、stage、production 用到了同一個 queue, 所以我在測試機器上傳的圖片, 都委派給其他 server 去做了, 而這邊 code 沒有 sync, 或是檔案也不在那台 instance 上, 所以就無法完成 task。

這告訴了我們, follow tutorial 還滿重要的。在 Using RabbitMQ 的 Setting up RabbitMQ 提到, 要設定 virtual host, 才會把 queue 給隔開。

Deployment

在 django 使用 gevent, 若是使用 gunicorn, 可以直接將 worker 換成 gevent


gunicorn app.wsgi:application --worker-class gevent

如果直接執行的話, 可以參考 django-longpolling-examplerungevent.py

12 十月

以 django 來開發網頁

今天剛好碰到以前的同事問我關於 django 開發網頁的事情。我才想到, 上一次想到 django 相關的 packages 似乎講得不夠詳細。這邊稍微補充一下。

Web Server

如果不是很 heavy 的網站, 流量不大的話, 其實 apache2 就很足夠了。個人偏好是因為從很早就開始使用 apache, 也習慣他的 configuration 了。至於如果常見大家所使用的 deployment, 就是使用 nginx 外加 gunicorn 了。
A Django setup using Nginx and Gunicorn 這篇文章寫得頗清楚的。我個人是使用 Ubuntu, 因此選用 upstart 來寫他的 service script。

Environment

上一段提到的部落格文章有特別提到一個東西就是 virtualenv, 個人也相當推薦使用。他會將你的 python environment cage 在某個目錄, 因此 django 所使用到的套件並不會跟系統的 python 混淆。Tools of the Modern Python Hacker: Virtualenv, Fabric and Pip 這篇文章有提到。目前我還沒有使用 fabric 來做 deployment, 不過 virtualenv + pip 就非常好用了。

Settings

Django package ship 出來的 settings.py 其實不太適合 development/production 使用。SplitSettings 這個頁面寫了很多種方式來把兩邊分開來。

Template

Django 1.4 的 template 其實已經比以前好用非常多, 不過看到 instagram 使用 jinja2, 再看到 jinja2 官網的說明, 就會想要做這個 optimization。缺點就是如果你有使用第三方套件, template tags 以及 plugin 可能需要自己重刻。比較常見的搭配方式就是 jinja2 + coffin

CSS / js compression

django 有幾個套件可以做這件事情, 我目前有使用的是 django-pipeline。其他 solution 可以參考 Django packages -- asset managers。用這個東西的時候, 如果有 include 額外自己寫的 js, 記得要將變數 export 出來給 window, 否則變數都會被 cage 起來。

幾個月前看到這篇很棒的文章 -- What Powers Instagram: Hundreds of Instances, Dozens of Technologies, 裏頭提到了非常多不同面向的 solution, 值得參考。剛剛也在 quora 上看到這個 What technology stack is Instagram built with? 裡面也提到不少東西。

01 十月

console.log in IE

測試功夫做得還不夠。今天早上同事打來說, 還是有很多客戶反應 IE 註冊都沒有任何的提示。我上次想說就已經看過也修了, 為什麼還是一樣。今天到公司自己測了一下, 都 ok。直到我跑到同事的電腦請他做一次給我看, 才發現我跟他測的差別。我每一次都開了 developer tools 在做測試 (既然是在 debug, 當然會把這個打開), 殊不知就因為我有打開就看不到 bug。

此時我大概猜到了, 我應該是用了 console.log 所以開 developer tools 的時候都正常, 一關掉就爛掉了。

所以加了一個避免爆炸的小 code

// For IE
if (typeof console === "undefined" || typeof console.log === "undefined") {
console = {};
console.log = function() { };
window.console = console;
}

因為有做 js compress, 所以要把 console 給 expose 到 window 這個物件, 不然這段 code 會被 cage 住而讀不到資料。

26 九月

Django + jinja2 + mptt

當初毅然決然的把 template 換成 jinja2, 其實真的是 over-optimized 了。不過既然都已經換了, 就換了, 代價就是 3rd-party package 有使用到 template tags 的, 要自己重寫!

最近在重新整修後臺系統, 索性也把 template 換成 jinja2, 不過這時麻煩了, 我們使用 django-mptt 來做 tree structure, 在 template 這邊有使用到 mptt 自己的 tags。有時候自己真的很衝動, 昨天就開始看 code, hack, 想要自己把它 port 成 jinja2 的版本。碰到重重的困難後, 突然發現 jinja2 自己就有 recursive 可以使用。而且也弄成了。

我真的是太衝動了。不過還好, 更了解 jinja2 的 extension 怎麼寫的, 也可以準備來 rework 之前寫的 pipeline tags for jinja2。

20 九月

bootstrap 的 navbar-fixed-top

如果使用 navbar-fixed-top 的話, 要記得在 body 加上 padding。沒有看文件直接參考別人的 code 真的是會碰到問題阿! Trace 了半天才發現 style 加在 body 上。

body {
padding-top: 60px;
}

緣由其實是我想要看有沒有 fluid + fixed 的 bootstrap layout 可以參考, 於是乎找到了 Bootstrap: Fixed gutter width in fluid layout? 這篇文章。他的方式就是讓中間的 fluid layout 空出左邊或右邊的 margin 達成。

18 九月

踩到 ubuntu libjpeg 的 bug

今天花了一些時間, 想要把 gunicorn 的 script 整理一下。於是找了幾個 solution, 最後決定搭配 upstart 以及一支自己寫的 start.sh 讓 gunicorn 跑起來。後來我發現有一個很奇怪的訊息, 每一次跑起來, 有 request 進來, 就會丟

Error opening file for reading: Permission denied

非常奇妙的事情在於, 不同權限執行 gunicorn 會有不同的結果。以上的錯誤發生在我用 root 執行 gunicorn --user=web 才會發生。我如果使用 web 執行 gunicorn, 或是用 root 執行 gunicorn (但是不加上 --user=web) 都不會有這樣的問題。

Trace code 了許久, 最後發現是在 import PIL 的這一行出錯

import Image from PIL

上網查了一下, 是 ubuntu libjpeg 的問題。Reference 第二篇寫得很明確來龍去脈。

 

Reference:

  1. Error opening file for reading: Permission denied
  2. seteuid apps report perror() on trying /proc/self/auxv