くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

Windows Subsystem for Linuxの導入とCygwinからの移行

Windows Subsystem for Linux(WSL)にUbutnu18.04が追加されたそうなので、
そろそろCygwinからの移行を考えたときの備忘録φ(..)メモメモ

インストール

  1. Windows Subsystem for Linux の有効化
    • 「プログラムと機能」>「Windows機能の有効化または無効化」から
    • Windows Subsystem for Linux」にチェックを入れて、再起動
  2. Microsoft Storeから「Ubuntu」を検索してインストール
  3. Ubuntuを起動して初期設定
    • ユーザ名とパスワードを聞かれれるので、設定

初期設定

1. TimeZoneの設定
$ sudo dpkg-reconfigure tzdata
2. アップデート
# Ubuntu.jaリポジトリの追加
$ wget -q https://www.ubuntulinux.jp/ubuntu-ja-archive-keyring.gpg -O- | sudo apt-key add -
$ wget -q https://www.ubuntulinux.jp/ubuntu-jp-ppa-keyring.gpg -O- | sudo apt-key add -
$ sudo wget https://www.ubuntulinux.jp/sources.list.d/bionic.list -O /etc/apt/sources.list.d/ubuntu-ja.list

# apt でアップデート
$ sudo apt update
$ sudo apt upgrade -y
$ sudo apt autoremove
3. 日本語ロケールの設定
$ sudo apt install -y language-pack-ja
$ sudo update-locale LANG=ja_JP.UTF-8
4. wsltty のインストール
  • ここからダウンロード&インストール
  • Powershell$ wslconfig /setdefault Ubuntu-18.04を実行してwslttyを切り替え(これをしないと起動できない。。)
5. dircolors-solarizedのインストール
$ sudo git clone https://github.com/seebi/dircolors-solarized
$ sudo chown -R user.user dircolors-solarized
$ ln -s /usr/local/src/dircolors-solarized/dircolors.ansi-dark ~/.dir_colors
6. wsl-utilsのインストール
$ cd ${HOME}/dotfiles
$ sudo git clone https://github.com/smzht/wsl-utils
$ sudo chown -R user.user wsl-utils
$ for i in `ls -1 | grep -v "cyg" | grep -v ".org"`;do sudo chmod +x ${HOME}/dotfiles/wsl-utils/${i} ;done
$ for i in `ls -1 | grep -v "cyg" | grep -v ".org"`;do sudo ln -s ${HOME}/dotfiles/wsl-utils/${i} /usr/local/bin/${i} ;done

cygwinからのデータ移行

1. home配下のファイルをコピー
2. screenの設定
  • sudo screenで起動
  • sudo chmod 755 /run/screen/で一般ユーザにも権限付与
3. SSH鍵の設定
  • コピーしたらアクセス権限を設定
chmod -R 600 ${HOME}/ssh
find -type f -name "*.pem" | xargs -I{} chmod 600 {}
find -type f -name "*.ppk" | xargs -I{} chmod 600 {}
4. /usr/local/libに配置しているやつをコピー
  • gibo
  • peco

参考にしたサイト様

Python2.7でGoogle Cloud Storageを使ってみる

GCS(Google Cloud Strage)を使う機会があったので、その時の備忘録φ(..)メモメモ
用意されているバインディングライブラリもシンプルでいい感じ♪

インストール

$ pip install --upgrade google-cloud-storage

pythonでファイルのアップロード

from google.cloud import storage

bucket_name = # bucket名
project_name = # project名

def upload_gs_file(uploaded_file, context_type):
    # Cloud StorageのClientを作成
    client = storage.Client(project_name)

    # Bucketを取得
    bucket = client.get_bucket(bucket_name)

    # アップロードしたいファイル名でBucketに新しいBlobを作成
    file_name = os.path.basename(uploaded_file.name)
    blob = bucket.blob(file_name)

    # Blobにファイルの内容をアップロード
    content_type =  'plain/text' # テキストファイルの場合
    blob.upload_from_string(
        uploaded_file.read(),
        content_type=content_type
    )

    # アップロードしたファイルのURIと公開用URLを取得
    gs_uri = 'gs://{}/{}'.format(bucket_name, file_name)
    gs_public_url = blob.public_url

pythonでファイルの削除

from google.cloud import storage

bucket_name = # bucket名
project_name = # project名

def delete_gs_file(gs_file_name):
    # Cloud StorageのClientを作成
    client = storage.Client(project_name)

    # Bucketを取得
    bucket = client.get_bucket(bucket_name)
    
    # Bucketから削除したいファイルのBlobを取得
    blob = bucket.blob(gs_file_name)
    
    # ファイルの削除
    blob.delete()

参考にしたサイト様

Spring BootでHTTPセッションをあつかう3つのパターン

Spring BootでHTTPセッションを使う方法は3通りあるらしい。その時の備忘録φ(..)メモメモ

  1. セッション属性(@SessionAttribute)をつかう
  2. セッションスコープBeanをつかう
  3. Http Sessionを直接つかう

セッション属性(@SessionAttribute)をつかう

  • 同一Controller内で完結する場合は、セッション属性をつかう
  • セッション属性で指定したクラスのオブジェクトをHTTPセッション内で管理してくれる
@Controller
@RequestMapping(value = "/user/")
@SessionAttributes(types = UserForm.class)
public class UserAddController {

    @ModelAttribute("userForm")
    public UserForm setupForm() {
        return new UserForm();
    }

    @RequestMapping(path = "/add", method = RequestMethod.GET)
    public String index(Model model) {
        return "user-add";
    }

    @RequestMapping(path = "/add", params = "redo", method = RequestMethod.POST)
    public String redo(Model model) {
        return index(model);
    }

    @RequestMapping(path = "/add", params = "confirm", method = RequestMethod.POST)
    public String confirm(@Validated UserForm form, BindingResult result, Model model) {

        if (result.hasErrors()) return index(model);

       return "user-add-confirm";
    }

    @RequestMapping(path = "/add", params = "complete", method = RequestMethod.POST)
    public String add(@Validated UserForm form, BindingResult result, Model model) {

        if (result.hasErrors())  return index(model);

        return "redirect:/user/add?complete";
    }

    @RequestMapping(path = "/add", params = "complete", method = RequestMethod.GET)
    public String complete(Model model, SessionStatus sessionStatus) {
        sessionStatus.setComplete();
        return "user-add-complete";
    }
}

セッションスコープBeanをつかう

  • 複数のController間で共有したい場合に使う
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserForm implements Serializable {
    // セッションスコープで使いたいBean
}
@Controller
@RequestMapping("/user/add")
public class UserAddController {
    @Autowired UserForm userForm;
}

@Controller
@RequestMapping("/user/edit")
public class UserEditController {
    @Autowired UserForm userForm;
}

Http Sessionを直接つかう

  • Http Sessionを直接使いたい場合は、ControllerでHttpSessionをインジェクトして使う
@Controller
public class FooController {
    
  @Autowired
  HttpSession session;  
  
  @RequestMapping(value = "/save", method = RequestMethod.GET)
  public String save() {
    // 保存
    session.setAttribute("data", "保存したいデータ");
    return "index"
  }
  
  @RequestMapping(value = "/load", method = RequestMethod.GET)
  public String load() {
    String data = session.getAttribute("data");  // 取得
    session.invalidate(); // クリア
    return "index"
  }

参考にしたサイト様

AWSのEC2にはスワップ領域がないので、自分で設定する

なんてことでしょう。t2.microやt2.smallなど小規模インスタンスの場合には、スワップ領域がないのです。
メモリ使用量が多めの場合には、メモリエラーになってしまうことも。

なので、自分でSwap領域を確保してあげなければいけません。ということで、その時の備忘録φ(..)メモメモ

スワップ領域を追加する

#!/bin/bash

# 1Mのブロックを512個で合計512Mのファイルを/swapfile1として作成
sudo dd if=/dev/zero of=/swapfile1 bs=1M count=512
# 644だとswaponのときに怒られるので、600にアクセス権限を変更
sudo chmod 600 /swapfile1
# スワップ領域を作成
sudo mkswap /swapfile1
# スワップ領域を有効化
sudo swapon /swapfile1

# 再起動してもスワップ領域がマウントされるように、/etc/fstabに追加
sudo sh -c 'echo "/swapfile1  none        swap    sw              0   0" >> /etc/fstab'

スワップの頻度を変更

スワップすると、ファイルI/Oが発生するので、遅くなることも。。
なので、スワップの頻度を少なく設定します。

# 現在の頻度を確認
cat /proc/sys/vm/swappiness
# => 60

# スワップ頻度を10に変更
echo 10 | tee /proc/sys/vm/swappiness
echo vm.swappiness = 10 | tee -a /etc/sysctl.conf

スワップ領域を元に戻す

# スワップ領域を無効化
swapoff /swapfile1

# スワップファイルを削除
rm -f /swapfile1

参考にしたサイト様

Springの監査情報で、だれがいつ作成or更新したかを自動で付与する(SpringBoot/SpringData JPA)

DBの情報で、作成者や作成日や最終更新者や最終更新日を自分で追加していたけど、 Springに該当の機能があったので、調べたときの備忘録

やることは簡単、2ステップ。

1. Configクラスを作る

@Configuration
@EnableJpaAuditing
public class JpaAuditorAwareConfig {

    @Bean
    public AuditorAware<UserEntity> auditorAware() {
        return new SpringSecurityAuditor();
    }

    public static class SpringSecurityAuditor implements
            AuditorAware<UserEntity> {

        @Override
        public UserEntity getCurrentAuditor() {
            SecurityContext context = SecurityContextHolder.getContext();
            Authentication authentication = context.getAuthentication();
            if (authentication == null || !authentication.isAuthenticated()) {
                return null;
            }

            return (UserEntity) authentication.getPrincipal();
        }

    }
}

2. Entityに@CreateDateとかをつける

@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@Entity
@EntityListeners(AuditingEntityListener.class)
@Table
public class FooEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @CreatedDate
    @Column(nullable = false)
    private LocalTime createdDate;  // 作成日

    @LastModifiedDate
    @Column(nullable = false)
    private LocalTime modifiedDate;  // 最終更新日

    @CreatedBy
    @OneToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "created_user_id")
    private UserEntity createdBy;   // 作成者
    
    @LastModifiedBy
    @OneToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "modifiyed_user_id")
    private UserEntity modifiedBy;  // 最終更新者
}

以上!!

参考にしたサイト様

Spring Securityのカスタマイズ、どこでなにするのか?のおぼえがき

Spring Boot/Spring Securityを使って、認証部分のカスタマイズについていろいろ調べてみた、ときの備忘録
というか、やってみたこと、というか、おぼえがき

認証全体の流れ

リクエストが来たら

  1. SecurityFilter/AuthenticationFilterを通って
  2. AuthenticationManagerがAuthenticationProviderを呼び出し、
  3. AuthenticationProviderがUserDetailsSerivceを呼び出し、
  4. UserDetailsSerivceが、UserDetailsを返す。
  5. 認証が成功すると、AuthenticationFilterが、AuthenticationSuccessHandlerを呼び出す
  6. 認証が失敗すると、AuthenticationFilterが、AuthenticationFailureHandlerを呼び出す

多いし複雑。。さらに、認証が行われると認証イベントが発生し、それもハンドリングできる。

データベース認証をカスタマイズしたい(UserDetailsSerivce+UserDetails)

以下の2つを用意すればOK

  • UserDetailsを実装した資格情報を格納するクラス
  • UserDetailsSerivceを実装したDBからUserDetailsを取得するクラス

前の記事でも書いているので省略。

wannabe-jellyfish.hatenablog.com

認証処理の前にリクエストをフィルタしたり、追加情報を使いたい(AuthenticationFilter)

  • 認証処理に行く前に何かしたい場合は、AuthenticationFilterの実装をする
  • form認証の場合、デフォルトではUsernamePasswordAuthenticationFilterが使われる
  • UsernamePasswordAuthenticationFilterを拡張してゴニョゴニョするのがよい
public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
     if (!request.getMethod().equals("POST")) {
   throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
  }
       String username = obtainUsername(request);
       String password = obtainPassword(request);
       // このあたりでゴニョゴニョする。
        
       UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

        // Allow subclasses to set the "details" property
       setDetails(request, authRequest);
       
       return this.getAuthenticationManager().authenticate(authRequest);
    }
}
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Java Configではこんな感じ
        http.addFilterAt(new MyUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

認証成功時の処理をカスタマイズしたい(AuthenticationSuccessHandler)

  • AuthenticationSuccessHandlerを実装したクラスを使う
  • デフォルトはForwardAuthenticationSuccessHandler?SavedRequestAwareAuthenticationSuccessHandler?のよう
  • ForwardAuthenticationSuccessHandlerの実装はこんな感じ。authenticationを見て、遷移先とかをゴニョゴニョできる
public class ForwardAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    private final String forwardUrl;

    /**
    * @param forwardUrl
    */
    public ForwardAuthenticationSuccessHandler(String forwardUrl) {
        Assert.isTrue(UrlUtils.isValidRedirectUrl(forwardUrl), "'" + forwardUrl + "' is not a valid forward URL");
        this.forwardUrl = forwardUrl;
    }

    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        request.getRequestDispatcher(forwardUrl).forward(request, response);
    }
}

認証失敗時の処理をカスタマイズしたい(AuthenticationFailureHandler)

  • AuthenticationSuccessHandlerを実装したクラスを使う
  • デフォルトはForwardAuthenticationFailureHandler?SimpleUrlAuthenticationFailureHandler?のよう
  • ForwardAuthenticationFailureHandlerの実装はこんな感じ。exceptionを見て、遷移先とかをゴニョゴニョできる
public class ForwardAuthenticationFailureHandler implements AuthenticationFailureHandler {

    private final String forwardUrl;

    /**
    * @param forwardUrl
    */
    public ForwardAuthenticationFailureHandler(String forwardUrl) {
        Assert.isTrue(UrlUtils.isValidRedirectUrl(forwardUrl), "'" + forwardUrl + "' is not a valid forward URL");
        this.forwardUrl = forwardUrl;
    }

    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);
        request.getRequestDispatcher(forwardUrl).forward(request, response);
    }
}

参考にしたサイト様

supervisorでデーモン化する

Djangoのbackground tasksをデーモン化したいなーと思ったので、その際の備忘録。

supervisorとは

インストール

$ sudo yum install supervisor
$ sudo pip install supervisor

yumでインストールするとpython26も一緒にインストールされる。
python27をインストールしていたので、yumだけだと動かなかった。。 なので、pipを使って、supervisorをインストールした。

インストールするとそれぞれ以下の場所にインストールされる

  • 起動用のスクリプト ... /etc/init.d/supervisord
  • コンフィグファイル ... /etc/supervisord.conf
  • コンフィグ用ディレクトリ ... /etc/supervisord.d ※includeするコンフィグの置き場
  • 本体のログファイル ... /var/log/supervisor/supervisord.log

起動・停止

yumでインストールするとserviceコマンドで管理できる

# 起動
$ sudo service supervisord start
# 停止
$ sudo service supervisord stop

設定方法

supervisord.confに以下のようなテンプレートが用意されているので、
適宜コメントインして、設定すればOK。

;[program:theprogramname]
;directory=/tmp              ; (default is not to cd during start)
;command=/bin/cat            ; the program (relative uses PATH, can take args)
;priority=999                ; the relative start priority (default 999)
;autostart=true              ; start at supervisord start (default: true)
;autorestart=true            ; retstart at unexpected quit (default: true)
;startsecs=10                ; number of secs prog must stay running (def. 10)
;startretries=3              ; max # of serial start failures (default 3)
;exitcodes=0,2               ; 'expected' exit codes for process (default 0,2)
;stopsignal=QUIT             ; signal used to kill process (default TERM)
;stopwaitsecs=10             ; max num secs to wait before SIGKILL (default 10)
;user=chrism                 ; setuid to this UNIX account to run the program
;log_stdout=true             ; if true, log program stdout (default true)
;log_stderr=true             ; if true, log program stderr (def false)
;logfile=/var/log/cat.log    ; child log path, use NONE for none; default AUTO
;logfile_maxbytes=1MB        ; max # logfile bytes b4 rotation (default 50MB)
;logfile_backups=10          ; # of logfile backups (default 10)

例としては以下の感じ

[program:ProcessTasks]
directory=/var/www/cgi-bin/django
command=python manage.py process_tasks
autostart=true
autorestart=true
user=root
logfile=/var/log/process_tasks.log

その他のデーモン化ツール

  1. deamonize tool ... http://cr.yp.to/daemontools.html
  2. systemd

参考にしたサイト様