togatttiのエンジニアメモ

過度な期待はしないでください.

Ansibleで、クライアントPCのファイルの存在チェック

Ansibleを使うとき、クライアント側の実行結果をトリガーにして何かする場合、 local_actionとregisterモジュールを組み合わせれば良い。

クライアントPC側で、あるファイルの存在を確認するためには、statモジュールを使う。

使用例

一般的なAnsibleのディレクトリ構造が以下のようにあり、commonは、

config.ymlをリモートマシンに送るrolesである。

tree .
.
├── inventory
│   └── hosts
├── roles
│   └── common
│       ├── files
│       │   └── config.yml
│       └── tasks
│           └── main.yml
└── site.yml

roles/common/tasks/main.yml の中身は次のように書いた。

ここでは、config.ymlが存在していれば、ファイルをリモートに転送して、

無ければ、ファイルの転送をスキップするように振り分ける。

# roles/common/tasks/main.yml
- name: check config.yml exists in local
  local_action: stat path="roles/common/files/config.yml"
  register: file
  ignore_errors: True

- name: copy config.yml to remote
  copy: src=config.yml dest=~/config.yml
  when: file.stat.exists

config.ymlがある場合

ansible-playbook -i inventory/hosts site.yml 

PLAY ***************************************************************************

TASK [setup] *******************************************************************
ok: [***.***.***.***]

TASK [common : check config.yml exists in local] *******************************
ok: [***.***.***.***]

TASK [common : copy config.yml to remote] **************************************
changed: [***.***.***.***]

PLAY RECAP *********************************************************************
***.***.***.***            : ok=3    changed=1    unreachable=0    failed=0

config.ymlがない場合

ansible-playbook -i inventory/hosts site.yml 

PLAY ***************************************************************************

TASK [setup] *******************************************************************
ok: [***.***.***.***]

TASK [common : check config.yml exists in local] *******************************
ok: [***.***.***.***]

TASK [common : copy config.yml to remote] **************************************
skipping: [***.***.***.***]

PLAY RECAP *********************************************************************
***.***.***.***            : ok=2    changed=0    unreachable=0    failed=0

Designate の413エラーの対処

OpenStack Designate で、ゾーン登録時に、エラーが出たので対応方法を残しておく。

下記の作業は、designateが置いてあるホストで、行う。

事象

ゾーン登録時に、下記のエラーが出た。

413 Request Entity Too Large

ソースコードを調べると、どうやら、Designateで持っているゾーン登録の閾値に達しているらしい。

github.com

ゾーンの上限値は、10。

$ curl http://localhost:9001/v1/quotas/noauth-project
{
  "api_export_size": 1000,
  "recordset_records": 20,
  "zone_records": 500,
  "zone_recordsets": 500,
  "zones": 10
}
対応

ゾーン登録の上限値を更新する。

designate.confのapiのquotasを有効にしていることを確認する。

$ grep 'quotas' /var/lib/designate/etc/designate/designate.conf
enabled_extensions_v1 = diagnostics, quotas, reports, sync, touch
enabled_extensions_v2 = quotas, reports

API経由で、上限値を更新する。

$ curl -X PUT -H 'Accept: application/json' -H 'Content-Type: application/json' -d '{"zones": 100}' http://localhost:9001/v1/quotas/noauth-project
{
  "api_export_size": 1000,
  "recordset_records": 20,
  "zone_records": 500,
  "zone_recordsets": 500,
  "zones": 100
}
参考

Quotas — designate 2.0.0.0b3.dev57 documentation

OpenStack Keystoneで、Designateを認証する

Designateは、既にインストールされていることを前提とする。

OpenStack Designate を試す : あかぎメモ

ちなみに、これで、Designate の仮装環境を用意した。

ここで紹介すること

  • KeyStone セットアップ
  • テナント登録
  • DesignateへのKeystone設定
  • Keystoneを使った認証デモ

OSは、Ubuntu14.04を使う。

Keystone セットアップ

インストール
# apt-get -y update 
# apt-get -y install keystone
データベース、ユーザ作成

データベースは、MariaDBを使う。

# mysql -uroot -e "CREATE DATABASE keystone;"
# mysql -uroot -e "GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'localhost' IDENTIFIED BY 'keystone';"
# mysql -uroot -e "GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'%' IDENTIFIED BY 'keystone';"
管理トークン発行
# openssl rand -hex 10
b5fca4a6d7e3ba1d69ac
設定ファイル変更

管理トークン、データベース、ログディレクトリ情報を追記する。

# diff -u /etc/keystone.conf.sample /etc/keystone/keystone.conf
--- /etc/keystone.conf.sample    2016-01-14 16:59:04.665864893 +0900
+++ /etc/keystone.conf  2016-01-15 10:58:45.350297815 +0900
@@ -10,6 +10,7 @@
 # paste application pipelines (for example, in keystone-paste.ini). (string
 # value)
 #admin_token = ADMIN
+admin_token = b5fca4a6d7e3ba1d69ac

 # The base public endpoint URL for Keystone that is advertised to clients
 # (NOTE: this does NOT affect how Keystone listens for connections). Defaults
@@ -141,6 +142,7 @@
 # is ignored if log_config_append is set. (string value)
 # Deprecated group/name - [DEFAULT]/logdir
 #log_dir = <None>
+log_dir = /var/log/keystone

 # (Optional) Uses logging handler designed to watch file system. When log file
 # is moved or removed this handler will open a new log file with specified path
@@ -560,6 +562,7 @@
 # Deprecated group/name - [DATABASE]/sql_connection
 # Deprecated group/name - [sql]/connection
 #connection = <None>
+connection = mysql://keystone:keystone@127.0.0.1/keystone

 # The SQLAlchemy connection string to use to connect to the slave database.
 # (string value)
ログディレクトリ作成
# mkdir /var/log/keystone
# chown keystone:keystone /var/log/keystone
テーブル作成
# keystone-manage db_sync
起動
# service keystone restart
keystone stop/waiting
keystone start/running, process 7461

エンドポイントにアクセスできていれば、正しく起動している。

$ curl -s http://127.0.0.1:5000/v2.0
{"version": {"status": "stable", "updated": "2014-04-17T00:00:00Z", "media-types": [{"base": "application/json", "type": "application/vnd.openstack.identity-v2.0+json"}, {"base": "application/xml", "type": "application/vnd.openstack.identity-v2.0+xml"}], "id": "v2.0", "links": [{"href": "http://127.0.0.1:5000/v2.0/", "rel": "self"}, {"href": "http://docs.openstack.org/api/openstack-identity-service/2.0/content/", "type": "text/html", "rel": "describedby"}, {"href": "http://docs.openstack.org/api/openstack-identity-service/2.0/identity-dev-guide-2.0.pdf", "type": "application/pdf", "rel": "describedby"}]}}

Keystone へテナント、ユーザ、ロール作成

python-keyclientを使用する。

python-keyclient インストール
# git clone https://github.com/openstack/python-keystoneclient.git
# cd ~/python-keystoneclient
# python install -r requirements.txt
Keystoneにテナントやユーザ、ロールを作成するPython スクリプト

Designateのエンドポイント http://10.200.19.40:9001/v1 に対して、

DNSaasというテナントを作成する。

adminUserというユーザに対して、パスワードは、secretwordでユーザ作成する。

#!/usr/bin/python
# ./keystone_create.py

from keystoneclient.v2_0 import client

component_url = 'http://10.200.19.40:9001/v1'
token = 'b5fca4a6d7e3ba1d69ac'
endpoint = 'http://10.200.19.40:35357/v2.0'
tenant_name = 'DNSaas'
description = 'test'
username = 'adminUser'
password = 'secretword'
role = 'admin'
service_name='designate'
service_type='dnsaas'

keystone = client.Client(token=token, endpoint=endpoint)
print keystone

print keystone.tenants.create(
        tenant_name=tenant_name, 
        description=description, 
        enabled=True)

tenants = keystone.tenants.list()
my_tenant = [x for x in tenants if x.name == tenant_name][0]
my_user = keystone.users.create(
        name=username, 
        password=password, 
        tenant_id=my_tenant.id)

role = keystone.roles.create(role)

keystone.roles.add_user_role(my_user, role, my_tenant)
service = keystone.services.create(
        name=service_name, 
        service_type=service_type, 
        description=description)
keystone.endpoints.create(
        region='RegionOne', 
        service_id = service.id,
        publicurl=component_url,
        adminurl=component_url,
        internalurl=component_url)

管理用トークンをヘッダーに追加して、登録されたテナントを確認する。

$ curl -H 'X-Auth-Token: b5fca4a6d7e3ba1d69ac' http://10.200.19.40:35357/v2.0/tenants
{"tenants_links": [], "tenants": [{"description": "hoge", "enabled": true, "id": "beac3004ba344ddc8d4e9be13e77ce0e", "name": "DNSaas"}]}

Designateで、Keystone認証

designate.confに、以下を追加、変更する。

認証方法に関して、

auth_strategy = keystone

認証トークンに関して、

[keystone_authtoken]
auth_host = 127.0.0.1
auth_port = 35357
auth_protocol = http
admin_tenant_name = DNSaas
admin_user = adminUser
admin_password = secretword

Designateを再起動する。

# cd /etc/init.d
# ls designate-* | xargs -I@ service @ restart

通常アクセスした時に、認証エラーになることを確認する。

# curl http://127.0.0.1:9001/v1
Authentication required
Keystone 認証
  1. Keystoneに、ユーザとパスワード情報を渡す。テナントへのアクセストークンを発行する。
  2. テナントへのアクセストークンとテナント名をKeystoneに渡して、Designateへのアクセストークンを発行する。
  3. アクセストークンを用いて、Designateのエンドポイントへアクセスする。
# アクセストークンを取得するPython スクリプト
#!/usr/bin/python

import json
from httplib import HTTPConnection

keystone_unscoped = '127.0.0.1:5000'
username='adminUser'
password='secretword'

conn = HTTPConnection(keystone_unscoped)
header = {'Content-Type':'application/json'}
req = {'auth': {'passwordCredentials': {'username': username, 'password': password }}}
json_req = json.dumps(req)
conn.request('POST','/v2.0/tokens', json_req, header)
json_res = json.loads(conn.getresponse().read())
access_token_id = json_res["access"]["token"]["id"]
conn.close()

conn = HTTPConnection(keystone_unscoped)
header = {'X-Auth-Token': access_token_id, 'Content-Type':'application/json'}
conn.request('GET', '/v2.0/tenants', None, header)
print json.dumps(json.load(conn.getresponse()), indent=2)
conn.close()

tenant = raw_input("\ntenant name: ")
conn = HTTPConnection(keystone_unscoped)
header = {'Content-Type':'application/json'}
req = {'auth': {'tenantName': tenant, 'token': {'id':access_token_id}}}
json_req = json.dumps(req)
conn.request('POST', '/v2.0/tokens', json_req, header)
json_res = json.loads(conn.getresponse().read())
print "===== below is access_token ====="
print json_res["access"]["token"]["id"]
conn.close()

使い方

$ chmod 755 ./get_auth_token.py
$ ./get_auth_token.py
{
  "tenants": [
    {
      "enabled": true,
      "description": "test",
      "name": "DNSaas",
      "id": "5a30147f9c184fc6b618fc16e06c2b66"
    }
  ],
  "tenants_links": []
}

tenant name: DNSaas
===== below is access_token =====
MIIE-QYJKoZIhvcNAQcCoIIE7jCCBOoCAQExDTALBglghkgBZQMEAgEwggNLBgkqhkiG9w0BBwGgggM8BIIDOHsiYWNjZXNzIjogeyJ0b2tlbiI6IHsiaXNzdWVkX2F0IjogIjIwMTYtMDItMDlUMDM6MjE6NTYuMjM5MTU4IiwgImV4cGlyZXMiOiAiMjAxNi0wMi0wOVQwNDoyMTo1MloiLCAiaWQiOiAicGxhY2Vob2xkZXIiLCAidGVuYW50IjogeyJkZXNjcmlwdGlvbiI6ICJ0ZXN0IiwgImVuYWJsZWQiOiB0cnVlLCAiaWQiOiAiNWEzMDE0N2Y5YzE4NGZjNmI2MThmYzE2ZTA2YzJiNjYiLCAibmFtZSI6ICJEZXNpZ25hdGUgRE5TYWFzIn19LCAic2VydmljZUNhdGFsb2ciOiBbeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTAuMjAwLjE5LjQwOjkwMDEvdjEiLCAicmVnaW9uIjogIlJlZ2lvbk9uZSIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTAuMjAwLjE5LjQwOjUwMDAvdjIuMCIsICJpZCI6ICIwYTdkZGNkZDZmODA0NjllYjMzZDJiZGQ5MmI2YzNkNyIsICJwdWJsaWNVUkwiOiAiaHR0cDovL2xvY2FsaG9zdDo5MDAxL3YxLyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJkbnNhYXMiLCAibmFtZSI6ICJkZXNpZ25hdGUifV0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJhZG1pblVzZXIiLCAicm9sZXNfbGlua3MiOiBbXSwgImlkIjogImNkYTlmYmFhNjZhZTQzNTViZGViOWIwMjJjOTUzMzEzIiwgInJvbGVzIjogW3sibmFtZSI6ICJfbWVtYmVyXyJ9LCB7Im5hbWUiOiAiYWRtaW4ifV0sICJuYW1lIjogImFkbWluVXNlciJ9LCAibWV0YWRhdGEiOiB7ImlzX2FkbWluIjogMCwgInJvbGVzIjogWyI5ZmUyZmY5ZWU0Mzg0YjE4OTRhOTA4NzhkM2U5MmJhYiIsICJkNjY2MGVkMzU0NDE0OWU0Yjc4YWQ1NzUxNzI5ZjIzMCJdfX19MYIBhTCCAYECAQEwXDBXMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVW5zZXQxDjAMBgNVBAcMBVVuc2V0MQ4wDAYDVQQKDAVVbnNldDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tAgEBMAsGCWCGSAFlAwQCATANBgkqhkiG9w0BAQEFAASCAQBWYPlk24npFFVrciVovHYLIUueg5pgV0zRa2cWT8RoWUxXNTcbIbSDCyRh+rbDXx3eCZaafcnddjlYJhGzXp9PD5qgpUhj0tynNN0pZPNklDKAFZvZqtzf8pCGj3RPjmTg-lo2ff5hBpRwsl0TZWnF8S0q-Mx7IemVI48Sairehk0UJ8GkU12cLqeS2K4rRVEYdY81GAuErodlRHvkaRsm5WgjKFjE3TpMNT0xdS+IvKnsE5TRt-6O9pbX+sAp+SGg1fb+XHPIW6L5o6TrFbQtruuoSB7aHLKlY75kYXYaicNyVdsa-gMRuya-93CKdMdwcvDQ0s2IGGVcximTRi+Y

アクセストークンを使って、Designateのエンドポイントにアクセスする。

# ACCESS_TOKEN_ID="<上で出した文字列>"
# curl -H "X-Auth-Token: $ACCESS_TOKEN_ID" http://127.0.0.1:9001/v1/servers
{
  "servers": [
    {
      "created_at": "2016-02-08T06:51:46.000000",
      "id": "06b696c2-b2e0-47ef-b348-de8e221e1b0b",
      "name": "ns1.example.com.",
      "updated_at": "2016-02-08T07:30:26.000000"
    },
    {
      "created_at": "2016-02-08T07:30:26.000000",
      "id": "2c593756-a82c-4372-9587-c4a4489b6724",
      "name": "ns2.example.com.",
      "updated_at": null
    }
  ]
}
参考

KeystoneのUnscoped TokenとScoped Tokenの違い - めもめも Software Defined Boden: OpenStack Keystone Workflow & Token Scoping

Designateの仮想環境作成は、ここを参考にした。

OpenStack Designate を試す : あかぎメモ

Jenkinsのジョブをコマンドラインから生成する

Jenkinsのジョブをコマンドラインから、生成する方法を調べてみた。

OSは、Ubuntu14.04。

結論から言うと、XMLファイルをjenkins-cli.jarの create-jobコマンドに与えればよい。

Jenkins CLI - Jenkins - Jenkins Wiki

以下の実行パスや、URLは各自の環境に読み替えること。

jenkins.example.comとなっている箇所は、自身のJenkinsが動作しているURLを指す。

テンプレート用のXMLファイル作成

生成するジョブのテンプレートとなるXMLファイルを作成する。 通常通り、UIからジョブを作成する。

ここでは、echo 'this is 01_job' をする簡単な01_jobを作成する。

そうすると、サーバ内に、以下のようなファイルが作成される。

jenkins@ubuntu:~$ cat /var/lib/jenkins/jobs/01_job/config.xml
<?xml version='1.0' encoding='UTF-8'?>
<project>
  <actions/>
  <description>this is 01_job</description>
  <keepDependencies>false</keepDependencies>
  <properties/>
  <scm class="hudson.scm.NullSCM"/>
  <canRoam>true</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
    <hudson.tasks.Shell>
      <command>echo &apos;this is 01_job&apos;</command>
    </hudson.tasks.Shell>
  </builders>
  <publishers/>
  <buildWrappers/>

Jenkins CLI

今回は、Jenkins CLIのcreate-jobコマンドを使い、ジョブを生成する。

Jenkins CLI は、コマンドラインから、Jenkinsを操作するためのjarファイルで、Jenkinsにパッケージされている。

まずは、自身のURL/jnlpJars/jenkins-cli.jar から、jenkins-cli.jarをダウンロードする。

$ wget http://jenkins.example.com/jnlpJars/jenkins-cli.jar

また、http://jenkins.example.com/cli のようなURLで、使えるコマンド一覧、 ヘルプが参照できる。

ダウンロードしたら、実際に使ってみる。

$ java -jar jenkins-cli.jar -s jenkins.example.com/ -i ~/.ssh/id_rsa version
1.627

$ java -jar jenkins-cli.jar -s http://jenkins.example.com/ -i ~/.ssh/id_rsa who-am-i
Authenticated as: togashik
Authorities:
  authenticated

-s には、jenkins のURL、-i には、秘密鍵を指定する。 秘密鍵は、ログインユーザに登録した公開鍵とペアになっているものを指定する。

早速、create-jobを使い、ジョブを生成してみる。

最後に与えた02_jobは、新規生成するジョブ名を指す。

$ cat /var/lib/jenkins/jobs/01_job/config.xml | java -jar jenkins-cli.jar -s http://jenkins.example.com/ -i ~/.ssh/id_rsa create-job 02_job

これで、ジョブが生成できたはずなので、get-jobで確認してみる。

$ java -jar jenkins-cli.jar -s http://jenkins.example.com/ -i ~/.ssh/id_rsa get-job 02_job
<?xml version='1.0' encoding='UTF-8'?>
<project>
  <actions/>
  <description>this is 01_job</description>
  <keepDependencies>false</keepDependencies>
  <properties/>
  <scm class="hudson.scm.NullSCM"/>
  <canRoam>true</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
    <hudson.tasks.Shell>
      <command>echo &apos;this is 01_job&apos;</command>
    </hudson.tasks.Shell>
  </builders>
  <publishers/>
  <buildWrappers/>

ただし、これでは、02_jobは01_jobの単なるコピーなので、設定に含めたシェルスクリプトecho 'this is 01_job' のままである。

これを、echo 'this is 02_job' としたいとき等、読み込むxmlファイルを変更する必要がある。

delete-jobで先ほどのジョブを削除する。

$ java -jar jenkins-cli.jar -s http://jenkins.example.com/ -i ~/.ssh/id_rsa delete-job 02_job

create-jobで、再生成する。

$ sed 's/01_job/02_job/' /var/lib/jenkins/jobs/01_job/config.xml | java -jar jenkins-cli.jar -s http://jenkins.example.com/ -i ~/.ssh/id_rsa create-job 02_job

おまけ

コマンドラインから、生成したジョブを既存のビューに追加する

Jenkins CLIを使う方法を試そうとしたけど、うまくいかなかったので、力づくでやる。

つまり、ビュー構造が定義されているconfig.ymlを手動で変更して、読み込ませる。

02_jobをblogというビューに追加する。

$ sed -n '/^\s*<name>blog/,/^\s*<\/jobNames>/p' /var/lib/jenkins/config.xml
      <name>blog</name>
      <filterExecutors>false</filterExecutors>
      <filterQueue>false</filterQueue>
      <properties class="hudson.model.View$PropertyList"/>
      <jobNames>
        <comparator class="hudson.util.CaseInsensitiveComparator"/>
        <string>01_job</string>
      </jobNames>

$ sed -i.bak -e '/<string>01_job<\/string>/a\ \ \ \ \ \ \ \ <string>02_job<\/string>' /var/lib/jenkins/config.xml

$ sed -n '/^\s*<name>blog/,/^\s*<\/jobNames>/p' /var/lib/jenkins/config.xml
      <name>blog</name>
      <filterExecutors>false</filterExecutors>
      <filterQueue>false</filterQueue>
      <properties class="hudson.model.View$PropertyList"/>
      <jobNames>
        <comparator class="hudson.util.CaseInsensitiveComparator"/>
        <string>01_job</string>
        <string>02_job</string>
      </jobNames>

Jenkinsを安全に再起動する。

$ java -jar jenkins-cli.jar -s http://jenkins.example.com/ -i ~/.ssh/id_rsa safe-restart

参考

Jenkinsはじめました - こしごぇ

Firefoxの証明書警告を自動でスキップする

自動テストで、Seleniumを使っているが、自己割当証明書のドメインをテストする たびに、例外証明書として、登録するのが手間だと思ったので、自動化でできないか調べてみた。

f:id:togattti1990:20150828172155p:plain

証明書警告とは、このような表示。。

自動で、証明書警告をスキップするためには、FirefoxアドオンのSkip Cert Errorを使う。

addons.mozilla.org

インストールしたら、設定を開き次のように設定を済ませる。

f:id:togattti1990:20150828173024p:plain

Domain whitelist には、ドメインもしくはIPの一部にマッチした場合、証明書の検証をスキップしてくれる。 複数サブドメインを利用することがある場合は、楽に設定を済ますことが出来る。

もっとおすすめの方法があれば、ぜひ教えてください。

ちなみに、Firefoxプロファイルの設定は、ここらへんが参考になると思います。

togattti.hateblo.jp