Goalist Developers Blog

JSでファイルダウンロードを実行したい場合はどうしたらいい?

一般的に、ファイルダウンロードのために

<a href="https://example.com/my_file.txt" download>click</a>

的なコードで行ってると思いますが、たまにリンクが事前に分からない状態であり、ボタンをクリックした後でリンクを作成してからダウンロードを実行する時もあります。その場合、サーバーが返してくれるリンクのダウンロード実行をjavascriptで行って欲しい時もあるかと思います。

普通のやり方

ほとんどの時、

document.location.assign(url);

window.open(url, '_self');

と書いて、実行できるかと思います。ただし、ファイルの種類によってブラウザーに怒られる可能性もあります。 この間まさに、

f:id:c-pattamada:20180517113207p:plain

と怒られました。 つまり、「本当のファイルがzipなのに、なんでtext扱いしてるの?!」と。 ただのワーニングなのです。でも解決があるかどうか、を調べて見ました。

まずは、

window.open(url, '_blank')

はどうでしょうか?

f:id:c-pattamada:20180517113225p:plain

確かにな、サイトが勝手に何かをダウンロードして欲しくないよね、と思いました。javascriptはそういうことのためにもいっぱい使われてますね。納得。

ですが、一方にあるポップアップブロッカーの存在すら気づいてないお客さんもいるらしい。ダウンロード期待してるのに、何も起こらなくて困ってて問い合わせが頻繁にくるというのが聞きましたので、このままじゃダメだねと思いました。

ということで、ポップアップブロッカーのCMを作りました。 違います。

元のワーニングありの状態に戻すか、別な方法を探すかという二つの選択肢がありました。

リンク作成後->更新してクリック。

まずはhtmlのリンクを作成します。

<a download id="downloadLink" #downloadLink style="display:none;"></a>

‘download’が書いてあるので、ブラウザーがリンクされてるファイルを開こうとせずに、ダウンロードする。

Angularの〇〇.component.tsの中からhtmlをアクセスする方法はこんな感じです:

@ViewChild('downloadLink') downloadLink: ElementRef;

では、このhtmlをどう編集すればいいでしょうか?

this.downloadService.getDownloadUrl(myVariables).subscribe(
       myUrl => { //サーバーからurlをもらって、
                 // 上記のリンクを更新して
        this.downloadLink.nativeElement.href = myUrl; 
        this.downloadLink.nativeElement.click(); 
                  //終わったら、クリックできなくする。
        this.downloadLink.nativeElement.removeAttribute('href');
        }
);

をやって見たら何も文句言わずにダウンロードできました。

結論

こういうものでしょうかな。ワーニング付けの一つめの方法と最後の方法のどっちのほうが好み次第だと思います。 個人的にワーニングをなくそうと頑張ってるつもりながら、2番目の方法は本来ユーザーがするはずのリンククリックをプログラムで実行してるのでちょっとづるいと思ってるところもありました。

JenkinsのPublish Over SSHプラグインでEC2上にjarを配布する

Gradleプロジェクトにしてjarをビルドしてるので
ポチッとな〜するだけでデプロイ作業完了できます

ビルド環境

  • Amazon Linux AMI 2017.09.1.20180307 x86_64 HVM GP2
  • Jenkins ver. 2.111

配布先サーバーもAWS EC2です

やってること

  • Gradleでjarをビルド
  • Jenkinsで配布
  • 場所をチョトダケ動かすヨ

手順

1. Jenkinsで配布先サーバーの登録

Publish Over SSH Plugin - Jenkins - Jenkins Wiki

Jenkinsの管理 > システムの設定 > Publish over SSH

Key
配布先への接続用公開鍵をコピペ

Name
判別しやすい名前をつける

Hostname
配布先のホスト

Username
配布先もec2 linuxなのでec2-userでいく

Remote Directory
なにも指定しなければ↑で指定したユーザーのホームディレクトリ

f:id:y-iio:20180509123510p:plain

Test Configurationで失敗する?
配布先サーバのセキュリティグループで、ビルドサーバからのssh接続を許可するのをお忘れなく

2. Jenkinsジョブの設定

2.1. Gradleでjarをビルドする

Gradle Plugin - Jenkins - Jenkins Wiki

Jenkinsジョブ > ビルド > Invoke Gradle script
Use Gradle Wrapper
Tasks にタスク名を指定

かんたん!

f:id:y-iio:20180509122525p:plain

2.2. 配布する

Jenkinsジョブ > ビルド後の処理 > Send build artifacts over SSH

Name
ドロップダウンでさっき登録したサーバが選べるようになっている

Transfer Sets
Source files
ビルド成果物までのパス

Remove prefix
これ指定しないと配布先にも同様のパスがつくられる

Remote directory
配布先のディレクトリを指定
サーバー設定のRemote Directoryでなにも指定してなければ
↑で指定したユーザーのホームディレクトリからの相対パス

Exec command
上書きして配布することができないので、いったん送りつけた後ファイルの場所を移動している

なんかEither Source files, Exec command or both must be suppliedとかエラーメッセージ出ているが無視

f:id:y-iio:20180509123526p:plain

これで終わり〜

IaC by Terraform ~DAY3: Terraform Commands (2)~

どうも,新卒エンジニアのナカノです.

今や完全に春真っ最中な時期ですが,暑さがまるで夏の様です.

そのため,日中は汗だくで辛いです.これでは夏に耐えられぬ....

さて,今回は前回の記事の内容の続きとなります.

前回はよく使われるTerraformのコマンドに関する内容でした.

今回の内容は,場合によって役立つTerraformのコマンドに関してです.

目 次
  • 場合によって役立つコマンド
    • 出力コマンド
      • graph
      • output
      • show
    • その他
      • console
      • get
      • import
      • providers
  • 最後に

場合によって役立つコマンド

出力コマンド

graph

設定内容或いはplanapplydestroyなどのコマンドの結果を,ビジュアルなものとして出力してくれるコマンドです.

これを実行すると設定間の関連などが視覚的に分かるため,確認作業を行う上では役立つかもしれません.

ただ,設定が多すぎると出力結果がかえって見辛くなるため,使いどころは考える必要があるかなと思います. www.terraform.io

output

ただ単にterraform outputを実行すると,設定された全ての出力値が表示されます.

また,コマンド実行の際に-jsonオプションを使うと,出力結果のフォーマットをJSON形式に変えることが出来ます.

JSON形式での出力が出来るため,例えばjqコマンドと組み合わせて出力値の利用が可能です.

他にも,オプションの利用により,terraform.tfstateの情報やmoduleの設定内容の出力も出来ます.

一見すると重要そうに見えないですがTerraformに慣れてくると有り難みが分かってくる,そんなコマンドです. www.terraform.io

show

このコマンドを実行すると,ファイルの設定内容をhuman-readableなフォーマットで出力してくれます.

outputコマンドは出力設定の内容しか出力しないのに対し,showコマンドは実装した設定の内容を出力します.

そのため,showコマンドはoutputコマンドよりも詳細な情報を画面に表示してくれます. www.terraform.io

その他

console

文字通りで,コンソールを扱うことが出来ます.一見すると役に立たなさそうなコマンドに思えます.

しかし例えば,このコマンドの実行後に,Terraformで使える関数などの挙動を確認することが出来ます.

挙動の確認なしにplanapplyを行うのは怖いため,挙動確認の点で割と重要なコマンドであると言えるでしょう. www.terraform.io

get

moduleと呼ばれるものを使って実装した場合,planapplyの前にこのコマンドを実行する必要があります.

これを実行すると.terraformディレクトリにmoduleに関するファイルが生成されます.

ただ,今のところはgetを使わずにinitplanapplyを行うだけでこと足りる様になっているみたいです.

実際に,私はTerraformを半年ほど使っていますが,このコマンドを実行せざるを得ない状況に遭遇したことがありません. www.terraform.io

import

Terraformで管理されていないインフラリソースを,Terraformの管理対象にすることが出来るコマンドです.

正確には,このコマンドにより「リソースの情報を追記される様にterraform.tfstateが書き換えられる」といった感じです.

もしterraform.tfstateがない場合は生成されますが,このファイルが既に存在する場合は単に書き換えが行われます.

そのため,このコマンドを実行した後は「最新化されたterraform.tfstateをもとに.tfファイルを作成して差分をなくす」作業が必要となります. www.terraform.io

providers

プロバイダーの情報を画面に表示させるコマンドです.表示形式はツリー構造です.

特に様々なプロバイダーを利用している場合であれば,作業ミスの防止のための確認として役立つかもしれません.

ただ,このコマンドは基本的には使われる機会が殆どないのではと思います. www.terraform.io

最後に

如何でしたでしょうか.普段は重要には感じられないが場合によっては非常に役立ちそうなものばかりですね.

次回は「terraform.tfstateに関連するコマンド」をご紹介したいと思います.

それでは,今回はこの辺りで筆を置かせて頂きます.

次回を乞うご期待ください.

10分でWordPressをEC2+CloudFront+ACMでHTTPSにする

「EC2上にあるWordPressをHTTPS化して!」と頼まれることは誰しも一度は経験すると思います。
今回はそんな時に10分で設定を終わらせる手順を残しておきます。
もちろん証明書はAWS Certificate Manager(ACM)を利用します。
CloudFrontの反映に30分とWordPressのDB置換が人によって時間がかかるので、その時間はご飯でも食べに行ってください。
最後の「まとめ」で詳しく書いていますが、ALB(ELB)をCloudFrontとEC2の間に挟まないと見た目上はHTTPSに見えていても、CloudFrontとEC2の間はHTTP通信(初期設定)でインターネットを経由します。

1. ACMで対象ドメインの証明書を作る

ACMのページで基本デフォルトのまま進めていけばできあがります。
注意点としては以下。特にリージョンは嵌りポイントの1つだと思います。

  • リージョンを東京ではなくバージニア北部を選ぶ
  • 確認メールで設定を完了する場合は最後の「検証方法の選択」画面でEメールの検証を選ぶ

CloudFrontはCDNなので特定リージョンではなく、グローバル扱いです。CloudFrontの設定画面でもグローバルになっています。作ったはずの証明書がCloudFrontの設定画面で出てこない!という場合は証明書のリージョンが間違っている場合が100%だと思います。

2. WordPressのあるEC2のパブリックDNSを確認する

f:id:t-moritsugu:20180424191806p:plain

ElasticIPを貼り付けたらパブリックDNSが消えたよ!という場合はサービス一覧からVPCにいき、対象のEC2に紐づいているVPCを選択し、アクションからDNS解決の編集とDNSホスト名の編集を「はい」にすればパブリックDNSは復活します。

f:id:t-moritsugu:20180424193320p:plain

3. CloudFrontを設定する

Create Distribution > WebのほうでGet Started
以下特に記載のないものはデフォルト値です。

Origin Settings

  • Origin Domain Name: EC2のパブリックDNS
  • Origin ID: 自動で入力されるので、変更したければ変える

Default Cache Behavior Settings

  • Viewer Protocol Policy: Redirect HTTP to HTTPS
  • Allowed HTTP Methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE
  • Cache Based on Selected Request Headers: All (Whitelistの場合は許可するヘッダを追加)
  • Forward Cookies: All (Whitelistの場合は許可するcookieを追加)
  • Query String Forwarding and Caching: Forward all, cache based on all (Whitelistの場合は許可するパラメータを追加)

Distribution Settings

  • Alternate Domain Names(CNAMEs): WordPressで公開しているサイトのドメイン
  • SSL Certificate: Custom SSL Certificateを選択し、ACMで作成した証明書を選択する

※証明書が出てこない場合は作成の際にリージョンが間違っているか、Eメールでの認証を行っていないために証明書の作成が完了していないかを確認してください。

特に記載のないものはデフォルトでOKなのでCreate Distributionして30分ぐらいまちます。

4. WordPressをHTTPSに対応させる

現行のWordPressはEC2で動いているのでAMIでバックアップを取ります。
DBがRDSなどでEC2上に無い場合、DBのバックアップもとります。
今回は以下のツールを利用してhttp://xxx.comhttps://xxx.comに置換しました。 interconnectit.com

wp-config.phpに以下を追記

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
        $_SERVER['HTTPS'] = 'on';
} elseif (isset( $_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO']) && $_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO'] === 'https') {
        $_SERVER['HTTPS'] ='on';
}

/* That's all, stop editing! Happy blogging.  ←これの前ぐらいに追記*/

CloudFrontはX_FORWARDED_PROTOヘッダをCLOUDFRONT_FORWARDED_PROTOに勝手に変換するので今回はWordPress側でCLOUDFRONT_FORWARDED_PROTOを判定することにしました。
CloudFront側でX_FORWARDED_PROTOをねじ込む方法もあると思います。

5. Route53でドメインをCloudFrontにむける

以下の値で設定します。

  • Name: WordPressで公開しているサイトのドメイン
  • Type: A
  • Alias: Yes
  • Alias Target: CloudFrontのDomainNameの値

まとめ

念のためですが、今回の構成ではCloudFrontとEC2の間はインターネットを通ります。
CloudFront作成後にOriginタブから選択してEditするとOrigin Protocol Policyという設定があり、デフォルトではHTTPです。従ってデフォルトではCloudFrontとEC2の間は全く暗号化されずれにインターネットを通ります。
とりあえずHTTPSになれば良いよ!ということであれば今回の方法でよいですし、そうでない場合でACMしか許されない場合はCloudFrontとEC2の間にALB(ELB)をはさめば良いです。ALBにはACMの証明書が置けるのでCloudFrontとALBの間をHTTPS通信にします。ALBとEC2の間の通信はインターネットに出ないので目的は達成できます。

ngx-datatableでソートしつつ特定の行を固定する!

angularでデータグリッド表示するのにngx-datatable使ってます

github.com

フロント側でのソート機能がついていますが、こんな感じで合計行まで動いてしまうのですよね

f:id:y-iio:20180413180915g:plain

突っ込んだデータの合計行だけは一番下に固定したいという望みを叶えるべく
ゴリラ的な方法でズズイと無理やりやってみました

マルチソートの対応はしない。漢らしい!

<ngx-datatable
        #dataTable
        [rows]="rows"
        [columns]="columns"
        [sorts]="sorts"
        (sort)="onSorted($event)">
</ngx-datatable>
public rows = [];
public columns = [];
public sorts = [];

@ViewChild('dataTable') private dataTable: DatatableComponent;
private ascSortedColumn: string = '';

public onSorted(event): void {
    // ここにくるとき、this.dataTable._internalRowsは常に昇順ソートがかかった状態になっている
    const columnName: string = event['column']['name'];
    // 一度明示的に昇順ソートした後だったら、ここで無理やり降順ソートの設定に書き換える
    if (this.ascSortedColumn === columnName) {
        this.ascSortedColumn = '';
        event['sorts'][0]['dir'] = 'desc';
        this.sorts = [{
            prop: event['sorts'][0]['prop'],
            dir: 'desc'
        }];
        this.rows = [...this.rows]; // 降順ソートを適用
        setTimeout(() => {
            this.moveSumRow(); // ライブラリ側の降順ソート処理が終わった頃合いを見計らう
        }, 100);
    } else {
        this.ascSortedColumn = columnName;
        this.moveSumRow();
    }
}

// ライブラリ側のソート処理が終わってから、合計行をいちばん後ろに移動させる
private moveSumRow(): void {
    const tmpRows = this.dataTable._internalRows.concat();
    const sumRowIndex: number = tmpRows.findIndex((row) => row.hasOwnProperty('x1field') && row['x1field'] === '合計');
    if (sumRowIndex < 0) {
        return;
    }
    const sumRow = tmpRows[sumRowIndex];
    tmpRows.splice(sumRowIndex, 1); // 合計行をいちばん後ろに移動
    tmpRows.push(sumRow);
    this.sorts = []; // テーブルのソートを解除 // ここで解除しておかないと合計行含めてソートし直されてしまう
    this.dataTable.sorts = []; // ほんとうにむりやりテーブルのソートを解除
    this.rows = [...tmpRows]; // 表を再描画
}

こんなかんじで、一瞬ペイッ!ガタッ!と動きます

f:id:y-iio:20180413180948g:plain

すごい力技だ!
現在選ばれているソート条件アイコンを見えなくすることで全てをうやむやにする!

力という名のパワーで全てを解決しました
男にはやらなきゃならねえ""瞬間とき""がある

Javaの未来

こんにちは、ゴーリストのチナパです。去年の9月より、オラクルさんがJavaをよりはやく更新するといい、同じ9月でJava 9がリリースされ、つい最近Java 10もリリースされました。しかも、今までみんなが使ってたJava 8は2019年の1月までしかアップデートされないらしいです。

f:id:c-pattamada:20180406164916j:plain

最近のオラクルのJava Client Roadmap Updateと言う物でもっと詳細が書かれましたのでそれを軽くサマリーしようと思いました。

http://www.oracle.com/technetwork/java/javase/javaclientroadmapupdate2018mar-4414431.pdf (英語です)

スケジュール

一番重要な情報はどんな風に更新が行う予定なのか、とどんな風にサポートが続くのか。故にそこから始めたいと思います。

Java 8は2019年1月まで公式アップデートが行う予定ですが、個人用(つまり、コーポレート用ではない)のためになら2020年までサポートが続くらしいです。

Java 11 (Java 18.9) は2018年の9月でリリースされる予定です、そしてそれは長期的なサポートに入るそうです(9と10は入りません)。

Java SE 11 (18.9) Platform JSR (384)

Java FX がJava 8 で2022年までサポートが残る予定ですが、Java 11からは外されている。swingとawtがJava 11に残るので、せめて2026年まで使えるらしいです。

変更点

では、Java 10の面白い更新に入りましょう。大きく分けると書き方の変化と裏の改善があります。追加機能いっぱいありますが、一番面白いと思った3つを以下にまとめてます。

変数の種類をコンテクストで理解する

var list = new ArrayList<String>();  // ArrayList<String>と理解してくれます

これはちょっとワクワクですね、自分はパイソンもよく使ってるのでちょっとだけでもコードが綺麗になりそう。一方、下手すると分かりにくくなりますね。 すでに存在してるコードの中のvar 変数は影響されないらしいです(つまり[code]int var = 5;[/code] がエラーを出さないです) そして、イニシャライズされない所にvarが使えない。

var x; //うまく行きません
var x, y = 0; //おっけー

裏の改善

スレッドローカルハンドシェーク:

マルティスレッドのセーフポイントの改善の機能です。結果的に現在のグローバルセーフポイント(全スレッドが中止する時)でしかできない活動をこのハンドシェーク機能で行えることによって効率性が高くなるようです。

CDSの改善=> AppCDS

CDSはJDK 5からありまして、ロード時間を減らすために編集しないクラスをarchiveし、そのarchiveされたクラスを高速でロードできるようになるシステムです。今まで、BootstrapClassLoaderしかできなかった事でしたが、この際AppClassLoader(故にAppCDS)もできるようになるためにエンタプライズ系のアプリのロード時間が結構減らせるらしいです。

他もありますので、下にオラクルの記事をリンクします!

オラクル、Java SE 10の一般提供を開始 | Oracle 日本

IaC by Terraform ~DAY2: Terraform Commands (1)~

どうも,新卒エンジニアのナカノです.

3月中旬辺りから段々と暖かくなってきましたね.

よく通る川沿いの道では沢山の桜の木が花を咲かせており,通勤時が非常に楽しいです.

さて,今回もTerraformに関する記事です.

前回は実行環境の準備に関する内容の記事でした.

今回の内容は,よく使われるTerraformのコマンドに関してです.

目 次
  • よく使われるコマンド
    • init
    • fmt
    • validate
    • plan
    • apply
    • destroy
  • 最後に

よく使われるコマンド

Terraformを用いてインフラリソースを作るには,まず.tfという拡張子の設定ファイルを作成します.

その後にリソース作成用のコマンドを実行すると,各.tfファイルの情報がある一つのJSONファイルにまとめられます.

これをterraform.tfstateというのですが,Terraformはこのファイルを基準にしてリソースの作成・改変・削除を行います.

以下は,それらを行う際によく用いられるコマンドです.

init

リソースの作成・改変・削除を行う際にまず行うべきコマンドです.

これが実行されると,実行場所に.terraformというディレクトリが作成されます.

このディレクトリがないとリソースの作成・改変・削除が行えないため,何よりも一番重要なコマンドです. www.terraform.io

fmt

設定ファイルのフォーマットを行う際に使われるコマンドです.

ただ,使用するエディタによってはフォーマット機能の付いたパッケージがあるため,人によってはあまり使われないかもしれません. www.terraform.io

validate

設定ファイルに文法エラーがあるか否かをチェックする際に使うコマンドです.

便利ですが,次に紹介するplanというコマンドが文法エラーを含めたエラーの検知を行ってくれるため,これもあまり使われないものかもしれません. www.terraform.io

plan

どういったリソースを作成,改変或いは削除するのかをTerraformが決めるために使われるコマンドです.

この実行によってterraform.tfstateと設定ファイルたちの内容の差分を検知し,Terraformの振る舞い方が決まります.

そのため,initコマンドの次に必須なコマンドであると言っても過言ではないでしょう.

ところで,planコマンドには次のよく使われるオプションがあります.

-target=resource

これを用いることで,ある特定のリソースのみに対してplanコマンドを実行させることが出来ます.

ある複数個のリソースに対してplanを行いたいのであれば,このオプションをplanに複数個並べて付ければよいです.

-destroy

削除対象のリソースたちの情報を見るためにこのオプションが使われます.

Terraformのリソース情報の差分認識を観察するには割と重要なオプションです.

-var 'foo=bar'

変数設定されているがその値が空の場合,このオプションが必要です.

このオプションを付けずにコマンドを実行すると,空の変数の値を対話的に要求されます.

その場合は,画面に変数値を入力してコマンド実行の続きを行えば大丈夫です.

-var-file=foo

Terraformには.tfvarsという拡張子のファイルがあり,これは変数設定を行う際に使われるファイルの一つです.

ファイルの内容は一見すると環境変数の設定ファイルの様に見えるかもしれません.

このオプションを使う場合は,オプション値に該当の.tfvarsファイルのパスを指定します.

もしこのオプションを使わない場合は,画面上で.tfvarsに書かれている変数の値を対話的に一つずつ要求されます.

www.terraform.io

apply

planコマンドの結果を元にリソースを作成・改変・削除するために使われるコマンドです.

この実行時でもエラーが検出されることがあるので,planが正常に終了したからといって油断するのは禁物です.

なお,このコマンドでは次のオプションがよく使われます.

-auto-approve

Terraformのバージョンが0.11.0になってからこのオプションが登場しました.

それ以前のバージョンではapplyを実行すると実行が終了するまでコマンドの処理が動き続けていました.

ところが,それではオペレーションミスなどが偶発することもあり,0.11.0以降では実行の許可を対話的に求められる様になりました.

さて,このオプションですが,その「実行許可の対話的要請」をスキップする様にしてくれるものです.

これを付けてapplyを実行すれば,0.11.0以前の様なapplyの挙動になります.場合によっては便利だったりします.

-target=resource, -var 'foo=bar', -var-file=foo

planのオプションにあるものと同様です. www.terraform.io

destroy

作成済みのTerraformで管理されたリソースを削除する際に使われるコマンドです.

実はapplyの実行時でもリソースが削除されることもあるのですが,違いは「destoryは削除のみに使われて,applyでは『リソースを作り直す」挙動を起こす時にリソースが削除される」といった感じです.

このコマンドでも次のよく使用されるコマンドがあります.

-auto-approve

applyのオプションにあるものと同様です.もしこれを使うのであれば,destoryの実行の前にterraform plan -destroyをすべきです.

最後に

よく使われるコマンドは上記の通りですが,基本的には

  • terraform init
  • terraform plan
  • terraform apply
  • terraform destroy

の4つを覚え,使い慣れる様にしておくとよいでしょう.

それでは,今回はここまでと致します.

次回は「場合によって役立つコマンド」についてご紹介致します.