2015年11月25日 星期三

[PHP] 尚未設定 phpMyAdmin 資料庫,某些進階功能將無法使用 @ Ubuntu 14.04

很久沒用 PHPMyAdmin 了,因為是都改用 Sequel Pro 啦!但開放給同事還是要用 PHPMyAdmin 就是了。簡言之,架設 PHPMyAdmin 後,在 /etc/phpmyadmin/config.inc.php 有個 controluser 跟 controlpass 要設定,之前都是偷懶用 root 權限,這次仔細研究一下,其實只要讓 controluser 可以管理 phpmyadmin database 即可,要限縮權限可以限縮到只能看到 phpmyadmin 資料庫!

至於 phpMyAdmin 資料庫未建立的,可以用以下招數進行處理:

$ ls /usr/share/doc/phpmyadmin/examples/create_tables.sql.gz
$ cp /usr/share/doc/phpmyadmin/examples/create_tables.sql.gz . && gunzip create_tables.sql.gz
$ mysql -h hostname -u controluser -p < create_tables.sql


如此一來,就會建立 phpmyadmin 資料庫,以及一堆 phpmyadmin.pma__* 開頭的資料表。

此外,如果在 AWS RDB 開很多 DB server 時,可以偷懶在 /etc/phpmyadmin/config.inc.php 添加位置,並且做完上述動作後,大家就可以透過 PHPMyAdmin 連線使用了!

$cfg['Servers'][$i] = $cfg['Servers'][$i-1];
$cfg['Servers'][$i]['host'] = 'new-aws-db-server-hostname';
$cfg['Servers'][$i]['controluser'] = 'phpmyadmin-pma-controller';
$cfg['Servers'][$i]['controlpass'] = 'password';
$i++;

iOS 開發筆記 - 把玩 Chromecast SDK 播放網路連結(圖片、影片)

買了一隻 Chromecast ,除了試用產品外,也想試試看 Chromecast SDK 。快速翻了一下 iOS App Development - ios sender 文件,還是不得其門而入 XD 最後還是乖乖看範例程式:https://github.com/googlecast/CastVideos-ios

簡言之,我是使用 Cocoapods 管理 Chromecast SDK 的:

$ vim Podfile
pod 'google-cast-sdk'
pod 'google-cast-remote-display-sdk'


接著寫一點程式,參考 CastVideos-ios 內的 CastDeviceController 範例了解整個流程。

總之,若要簡單播放一個 URL ,需要依序完成以下動作:

  1. 搜尋 chromecast device 並實作 GCKDeviceScannerListener 偵測裝置
    • GCKFilterCriteria *filterCriteria = [GCKFilterCriteria criteriaForAvailableApplicationWithID:kGCKMediaDefaultReceiverApplicationID];
    • self.chromecastScanner = [[GCKDeviceScanner alloc] initWithFilterCriteria:filterCriteria];
    • [self.chromecastScanner addListener:self];
    • [self.chromecastScanner startScan];
  2. 透過 - (void)deviceDidComeOnline:(GCKDevice *)device 偵測到後,進行連線
    • self.chromecastManager = [[GCKDeviceManager alloc] initWithDevice:self.chooseDevice clientPackageName:[NSBundle mainBundle].bundleIdentifier];
    • self.chromecastManager.delegate = self;
    • [self.chromecastManager connect];
  3. 連線裝置後,透過 Launch application 跟 Chromecast Device 進行溝通
    • [self.chromecastManager launchApplication:kGCKMediaDefaultReceiverApplicationID];
  4. 透過 - (void)deviceManager:(GCKDeviceManager *)deviceManager didConnectToCastApplication:(GCKApplicationMetadata *)applicationMetadata sessionID:(NSString *)sessionID launchedApplication:(BOOL)launchedApplication; 偵測完成 chromecast app 程式啟動並建立 GCKMediaControlChannel
    • self.mediaControlChannel = [[GCKMediaControlChannel alloc] init];
    • self.mediaControlChannel.delegate = self;
    • [deviceManager addChannel:self.mediaControlChannel];
    • [self.mediaControlChannel requestStatus];
  5. 播放 Resource,以 http://www.w3schools.com/html/mov_bbb.mp4 為例
    • NSMutableArray *tracks = [[NSMutableArray alloc] init];
    • GCKMediaMetadata *metadata = [[GCKMediaMetadata alloc] initWithMetadataType:GCKMediaMetadataTypeGeneric];
    • GCKMediaInformation *mi = [[GCKMediaInformation alloc] initWithContentID:@"http://www.w3schools.com/html/mov_bbb.mp4" streamType:GCKMediaStreamTypeNone contentType:nil metadata:metadata streamDuration:0 mediaTracks:tracks textTrackStyle:[GCKMediaTextTrackStyle createDefault] customData:nil];
    • [self.mediaControlChannel loadMedia:mi autoplay:YES];

如此一來 Chromecast device 就會播放指定的連結啦。

2015年11月18日 星期三

Ansible 筆記 - 透過 find-package 找到指定安裝檔進行遠端部署 @ Ubuntu 14.04

手癢貢獻一個 ansible role 出去:changyy.find-package 。透過 find-package 功能,可以將包裝好的 package 複製到遠端機器安裝,這個方式可以偷懶省去架設 package server (例如 Yum Server)。

以下是簡易的範例,透過 unix find 指令,找尋剛製作好的 package ,把它記錄在變數中:

$ mkdir -p ansible-test/roles && cd ansible-test && ansible-galaxy install changyy.find-package -p roles/
- downloading role 'find-package', owned by changyy
- downloading role from https://github.com/changyy/ansible-role-find-package/archive/master.tar.gz
- extracting changyy.find-package to roles/changyy.find-package
- changyy.find-package was installed successfully

$ vim test.yml
---
- hosts: localhost
  roles:
  - { role: changyy.find-package, package_dir: "/data/rpm/production/" , package_name_prefix: "package-*" }

- hosts: 127.0.0.1

  tasks:
  - name: copy package
    copy: src="{{hostvars['localhost']['package_path']}}" dest=/tmp

$ ansible-playbook test.yml


連續動作還可以發佈至指定機器上,詳情請見:https://github.com/changyy/ansible-role-find-package

Ansible 筆記 - 找尋本機端資源並部署至遠端機器,包含複雜 shell 指令、資源尋找錯誤處理、hosts 之間變數傳遞等

這個需求其實還滿簡單實現的,但為了想要達成更仔細的錯誤偵測,後來越改越複雜 XD 順便筆記一下。完整的使用情境:每次部署遠端機器前,本地端會有一個 package 產出(rpm),透過 find 指令找到最新產出的 package 後,再部署到遠端機器(其實也可以把架設 yum server 來搞定啦 XD)

最簡單的方式,使用 vars 紀錄:

- hosts: YourTargetServers

  vars:
    rpm_dir: "/data/rpm/production/"
    rpm_name_prefix: "packagename*"
    rpm_find_command: "find {{ rpm_dir }} -name '{{ rpm_name_prefix }}' -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d ' ' "
    rpm_path: "{{ lookup('pipe', 'rpm_find_command') }}"

  tasks:
    - name: find rpm prefix name
      debug: msg="{{rpm_name_prefix}}"

    - name: find rpm command
      debug: msg="{{rpm_find_command}}"

    - name: find rpm path
      debug: msg="{{rpm_path}}"


這樣算是收工了,但是 rpm_path 若沒找到時,卻無法有洽當的錯誤偵測 Orz

所以第一次再改成這招:

- hosts: YourTargetServers

  vars:
    rpm_dir: "/data/rpm/production/"
    rpm_name_prefix: "packagename*"
    rpm_find_command: "find {{ rpm_dir }} -name '{{ rpm_name_prefix }}' -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d ' ' "

  tasks:
    - name: find rpm prefix name
      debug: msg="{{rpm_name_prefix}}"

    - name: find rpm command
      debug: msg="{{rpm_find_command}}"

    - name: find rpm path
      local_action: command /bin/bash -c "{{ rpm_find_command }}"
      sudo: False
      failed_when: " '' != rpm_path_result.stderr"

    - name: get rpm path
      debug: msg="{{ rpm_path_result.stdout }}"


但這樣仍有個缺點,那就是若有 roles 等一堆工作,會變成那堆工作做完才會跑 tasks,這時就會希望先偵測本地端的資料在跑 roles 工作,於是乎又改成:

- hosts: loclahost

  vars:
    rpm_dir: "/data/rpm/production/"
    rpm_name_prefix: "packagename*"
    rpm_find_command: "find {{ rpm_dir }} -name '{{ rpm_name_prefix }}' -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d ' ' "

  tasks:
    - name: find rpm prefix name
      debug: msg="{{rpm_name_prefix}}"

    - name: find rpm command
      debug: msg="{{rpm_find_command}}"

    - name: find rpm path
      local_action: command /bin/bash -c "{{ rpm_find_command }}"
      failed_when: " '' != rpm_path_result.stderr"

    - name: get rpm path
      debug: msg="{{ rpm_path_result.stdout }}"

- hosts: YourTargetServers

  vars:
    rpm_path: "{{ hostvars['localhost']['rpm_path_result']['stdout'] }}"

  tasks:
    - name: find rpm path
      debug: msg="{{rpm_path}}"


如此一來,就可以先確保在 localhost 把資源準備齊了,再進行遠端部署動作,也包含偵錯處理啦。

2015年11月17日 星期二

Ansible 筆記 - 動態取得 EC2 機器進行發佈更新 (Dynamic Inventory) @ Ubuntu 14.04

摸了好一陣子,終於搞懂了 :P 簡單的說,採用 Dynamic Inventory 進行動態取得機器列表,此例是透過 EC2 相關工具來取得的。

$ echo `EC2_INI_PATH=ec2.ini AWS_ACCESS_KEY_ID=KEY_ID AWS_SECRET_ACCESS_KEY=ACCESS_KEY python ec2.py --refresh-cache`
{ "_meta": { "hostvars": { "IP" : { ... } } } }


其中 ec2.ini 內容:

[ec2]

#https://raw.githubusercontent.com/ansible/ansible/devel/contrib/inventory/ec2.ini
#regions = all
regions = ap-northeast-1
regions_exclude =

destination_variable = public_dns_name
vpc_destination_variable = ip_address
route53 = False

cache_path = /tmp
cache_max_age = 0

rds = False
elasticache = False

#instance_filters = tag:Ansible=*


整體上,執行 ansible-playbook 方式就改成:

$ ANSIBLE_HOST_KEY_CHECKING=false EC2_INI_PATH=ec2.ini AWS_ACCESS_KEY_ID=KEY_ID AWS_SECRET_ACCESS_KEY=ACCESS_KEY ansible-playbook mysite.yml -i ec2.py --private-key=ansible-deploy.pem

並且在 mysite.yml 中定義的 hosts 也需調整,例如想要透過 EC2 上的 tag 資訊,例如我對 EC2 上的機器標記 Tag 為 Ansible=deploy 機器發佈,這時可以先透過 python ec2.py 觀看想要的 tag 被轉成什麼,接著再去修改 mysite.yml 的 hosts 資訊即可。而 ANSIBLE_HOST_KEY_CHECKING=false 是用在略過 ssh key checking

例如:

$ echo `EC2_INI_PATH=ec2.ini AWS_ACCESS_KEY_ID=KEY_ID AWS_SECRET_ACCESS_KEY=ACCESS_KEY python ec2.py --refresh-cache`
{ "_meta": { "hostvars": { "IP" : { ... } } }, "tag_Ansible_deploy": [ "IP" ] }

$ cat mysite.yml
- hosts: tag_Ansible_deploy
  ...


最後一提,此例使用的 ec2.py 是從官方文件提到的,執行時需安裝 python-boto 環境,此例為了搭配 Jenkins 使用,盡可能把執行 AWS API 所需的資料都透過環境變數傳遞。