修改默认shell的bash

June 1st, 2011 yakjuly No comments

sudo vi /etc/passwd

会看到所有用户的权限以及使用的bash

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
syslog:x:101:103::/home/syslog:/bin/false
sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
ntpd:x:103:108::/var/run/openntpd:/bin/false
mysql:x:104:109:MySQL Server,,,:/var/lib/mysql:/bin/false
yakjuly:x:1000:1000::/home/yakjuly:/bin/sh

把最后yakjuly的移行的sh改成bash 即可

sh 和 bash 是两个不同的shell,linux下有很多种shell。
sh比较小,但是功能没有bash多,bash用得比较普遍

Categories: linux Tags:

authorized_keys立即生效

June 1st, 2011 yakjuly No comments
我将公钥拷贝成authorized_keys之后,为什么公钥认证没有生效?
解决方法:

通常这是由于$HOME,$HOME/.ssh的文件权限造成的,或者是$HOME/.ssh/authorized_keys的权限超过了sshd默认允许的权限。

如果是这样,可以执行下面的命令去解决这个问题:

$ chmod go-w $HOME $HOME/.ssh
$ chmod 600 $HOME/.ssh/authorized_keys

 

Categories: linux Tags:

wordpress迁移点滴

June 1st, 2011 yakjuly No comments

昨天把主机从dreamhost换到了linode,虽然觉得dreamhost很不错 但是没有root权限始终有点不快。

今年打算把服务器,运维等知识好好补充一下,于是买了口碑一直不错的linode的VPS。

第一天的任务就是 迁移博客。

1. scp把wordpress文件 都拷贝至新主机上

2.apt-get 安装mysql php5 php5-mysql php5-cgi libfcgi-dev spawn-fcgi nginx

3.使用spawn-fcgi 脚本 启动php5-cgi进程

sudo spawn-fcgi -f /usr/bin/php5-cgi -a 127.0.0.1 -p 9000 -C 3 -P /var/run/php5-cgi.pid

4.配置nginx

在/etc/nginx/sites-enabled下创建 yakjuly.com文件

server {
        listen   80;
        server_name yakjuly.com;

        access_log  /home/yakjuly/applications/yakjuly.com/log/access.log;
        error_log /home/yakjuly/applications/yakjuly.com/log/error.log;
        rewrite /wp-admin$ $scheme://$host$uri/ permanent;

        location / {
                root   /home/yakjuly/applications/yakjuly.com;
                index  index.php index.html index.htm;

                if (-f $request_filename/index.html){
                        rewrite (.*) $1/index.html break;
                }
                if (-f $request_filename/index.php){
                        rewrite (.*) $1/index.php;
                }
                if (!-e $request_filename){
                         rewrite . /index.php;
                }
        }

        location ~ .*\.php$ {
                include /etc/nginx/fastcgi_params;
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_index index.php;
                fastcgi_param   SCRIPT_FILENAME /home/yakjuly/applications/yakjuly.com$fastcgi_script_name;
        }
}
rewrite /wp-admin$ $scheme://$host$uri/ permanent;
解决了 /wp-admin 和/wp-admin/ 产生的url地址不一致的错误。
5.wordpress中文显示乱码。
在dreamhost时数据库是latin1,在导入linode时已经转化为了utf8 而且在mysql console中显示正常,说明是php的设置问题。
添加以下内容到wp-config.php
define('DB_CHARSET', 'utf8');
define('DB_COLLATE', 'uft8_general_ci');
6.域名指向
登陆godaddy设置域名A记录指向新主机ip地址
10分钟后就生效了 感叹godaddy的神速 V5
新blog的访问速度明显比原来快得多。
Categories: ubuntu, 杂七杂八 Tags:

数据库备份导入乱码问题

May 30th, 2011 yakjuly No comments

备份数据库时需要知道原来数据库的文件编码格式是什么。

show variables like “%character%”

看到的结果可能是latin1可能是gbk可能是utf8 代表着你在原来数据存储文字编码的格式,在备份时需要设定–default-character-set。不设定则默认时utf8

mysql执行导出

mysqldump -uyakjulycom -pxxxxx -h mysql.yakjuly.com –default-character-set=latin1 yakjuly_com > yakjuly_com.sql

这样在yakjuly_com.sql文件中 的中文内容就能显示正确。

那么再导入另外一个数据库

本地的数据库设定了 character-set是uf8 如果直接source则在数据库中仍然显示乱码

原因是在yakjuly_com.sql内容的开头有定义

/*!40101 SET NAMES latin1 */;

把latin1替换为utf8 保存,然后再创建数据库source该文件或 执行

mysql -uroot -p –default-character-set=utf8 -f yakjuly_com < yakjuly_com.sql

这样数据库中的中文就显示正确了

 

Categories: database, 杂七杂八 Tags:

系统接口设计

May 24th, 2011 yakjuly No comments

最近的工作redmine的二次开发,需要频繁的与别的系统打交道,在写接口这方面的代码 有了点心得写下来 分享一下。

首先 redmine作为一个前端展示给客户的系统,需要和 翻译系统,代码管理系统,SDK管理系统交互。

这三个系统 通过普通的Net::HTTP请求,返回内容。

返回内容格式不尽相同,

1.翻译系统直接返回 xml字符串,

2.sdk系统返回 {“code”: “200″, “data”: “xxxx”} 或 {“code”: “400″, “data”: ” xxxx”, “message”: “xx wrong”}

3.代码管理系统返回 {“status”: 0, “val”: “xxxxx”, } 或  {“status” : -1, “err”: {“message”: “xxxx”, “event”: “xxx”}}

我希望无论请求哪个接口都能在日志种记录下来,发生错误时能有合适的客户提示,代码不要重复同时也要便于修改。

定义加强版Net::HTTP

require "net/http"
require "tempfile"
require "base64"
require "digest"

class EnhancedNetHttp

  class Error < StandardError; end

  @@default_logger = Logger.new(Rails.root.join("log/net_http.log"))
  def self.default_logger
    @@default_logger
  end

  USER_AGENT    = "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6"
  BOUNDARY      = "---xxxxxxxxxxxxxxxxxx"
  CONTENT_TYPE  = "multipart/form-data; boundary=#{BOUNDARY};"

  attr_accessor :error_klass

  def initialize(*args)
    options = args.extract_options!
    self.logger = options[:logger]
    self.error_klass = options[:error_klass]
  end

  def logger
    @logger || EnhancedNetHttp.default_logger
  end

  def logger=(new_logger)
    @logger = new_logger
  end

  def error_klass
    @error_klass || EnhancedNetHttp::Error
  end

  def error_klass=(new_error_klass)
    @error_klass = new_error_klass
  end

  def post_multipart_form(url, params = {})
    uri = URI.parse(url)
    http = Net::HTTP.new(uri.host, uri.port)

    http.request(multipart_request(uri, params))
  end

  def post_form(url, params = {})
    uri = URI.parse(url)

    response = Net::HTTP.post_form(uri, params)

    if response.is_a?(Net::HTTPSuccess)
      logger.info format_message(uri, "POST", response, params)
    else
      raise error_klass.new(format_message(uri, "POST", response, params))
    end
    response
  end

  def get_response(url)
    uri = URI.parse(url)
    response = Net::HTTP.get_response(URI.parse(url))

    if response.is_a?(Net::HTTPSuccess)
      logger.info format_message(uri, "GET", response)
    else
      raise error_klass.new(format_message(uri, "GET", response))
    end
    response
  end

  def oauth_post(url, params = {})
    uri           = URI.parse(url)
    auth_header   = oauth_header(url, params)
    data          = ActiveSupport::JSON.encode(params)

    response = Net::HTTP.start(uri.host, uri.port) {|http|
      http.request_post(uri.path, data, auth_header)
    }

    if response.is_a?(Net::HTTPSuccess)
      logger.info format_message(uri, "OAUTH POST", response, params)
    else
      raise error_klass.new(format_message(uri, "OAUTH POST", response, params))
    end
    response
  end

  private

  def oauth_header(url, params= {})
    oauth = {
      "oauth_consumer_key" => "xxxxxxxxxxxx",
      "oauth_signature_method" => "HMAC-SHA1",
      "oauth_timestamp" => Time.now.to_i,
      "oauth_nonce" => Time.now.to_i,
      "oauth_version" => "1.0"
    }
    data = ActiveSupport::JSON.encode(params)
    param_string  = oauth.keys.sort.collect{ |item| "#{item}=#{oauth[item]}"}.join('&')
    base          = 'POST&' << CGI.escape(url) << '&' << CGI.escape(param_string)
    base          << "&#{CGI.escape(data)}" unless params.blank?
    signature = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), "xxxxxxxxxxxxxxxxxxxxxx", base))
    oauth["oauth_signature"] = signature.strip
    header_info = oauth.keys.sort.collect{ |item| "#{item}=\"#{oauth[item]}\""}.join(',')
    {"Authorization" => "OAuth:" + header_info}
  end

  def multipart_request(uri, params = {})
    request = Net::HTTP::Post.new(uri.request_uri)
    post_body = []
    params.stringify_keys.each do |key, value|
      post_body << "--#{BOUNDARY}\r\n"
      post_body << to_multipart(key, value)
    end
    post_body << "--#{BOUNDARY}--\r\n" unless post_body.empty?

    request.body = post_body.join
    request["Content-Type"] = CONTENT_TYPE
    request["User-Agent"] = USER_AGENT
    request
  end

  def to_multipart(key, value)
    if value.class == Tempfile
      "Content-Disposition: form-data; name=\"#{CGI::escape(key)}\"; filename=\"#{value.original_filename}\"\r\n" <<
        "Content-Type: \"application/octet-stream\"\r\n\r\n#{value.read}\r\n"
    elsif value.respond_to?(:path) and value.respond_to?(:read)
      "Content-Disposition: form-data; name=\"#{CGI::escape(key)}\"; filename=\"#{value.path}\"\r\n" <<
        "Content-Type: \"application/octet-stream\"\r\n\r\n#{value.read}\r\n"
    else
      "Content-Disposition: form-data; name=\"#{CGI::escape(key)}\"\r\n\r\n#{value.to_s}\r\n"
    end
  end

  def format_message(uri, method, response, params = {})
    "#{Time.now} [#{response.class.name}] #{method} #{uri} \n #{params.inspect if params.present?}"
  end

end

这里的EnhancedNetHttp就是相当于一个NetHttp请求的代理,这个是读Gary的blog想到的。

以前在javascript中 经常写回调函数,用于在多个方法中交互,在这里我就想 为何不传入错误类型 来细化请求错误的原因呢?

于是在EnhancedNetHttp里就有了 logger 与 error_klass

post_multipart_form 和 oauth_post 则是在Net::HTTP的基础上增加的2个方法。

调用接口时则使用EnhancedNetHttp类来负责发送请求。

接下来就非常简单了 对三个不同系统的接口写三个Service,配置不通的错误类型和日志。这样方便反映错误。

实际上调用接口出错 我认为发让系统邮件给开发人员会比较好,第一时间发现错误总比过了很久去日志里查要好。

class Sdk::Service
  class Error < StandardError; end

  @@logger    = Logger.new(Sdk.config[:log_path])
  cattr_reader :logger

  def self.net_http
    @net_http ||= EnhancedNetHttp.new(:logger => logger, :error_klass => Sdk::Service::Error)
  end

  attr_accessor :host, :platform

  def initialize(*args)
    options = args.extract_options!
    options.assert_valid_keys(:host, :platform)

    self.host = options[:host] =~ /\/$/ ? options[:host].chop : options[:host]
    self.platform = options[:platform]
  end

  def admin_user_query(user_id)
    url = "/xxxxxxx/xxxxx"
    params = {:abc => user_id, :efg => 456}
    get_json(url, params)
  end

  def admin_user_xml(version_id)
    url = "/bbbbb/cccccl"
    params = {:version => version_id}
    get_xml(url, params)
  end

  def admin_owned_item_xml(version_id)
    url = "/ttttttttt/uuuuu"
    params = {:version => version_id}
    get_xml(url, params)
  end

  private

  def get_response(full_url, params)
    url = "#{full_url}?#{params.to_query}"
    Sdk::Service.net_http.get_response(url)
  end

  def oauth_post(url, params = {})
    Sdk::Service.net_http.oauth_post(url, params)
  end

  def get_xml(url_path, params = {})
    response = oauth_post("#{host}#{url_path}", params)
    Zlib::GzipReader.new(StringIO.new(response.body)).read
  end

  def get_json(url_path, params = {})
    response = oauth_post("#{host}#{url_path}", params)
    json     = ActiveSupport::JSON.decode response.body
    if json["code"] == 200
      HashWithIndifferentAccess.new(json["data"])
    else
      logger.error("Response [#{json['code']}]: #{url_path} - #{json.inspect}")
      raise Sdk::Service::Error.new(json["message"])
    end
  end

end

在重构代码的时候还用到一个有趣又简单的代理

class Translate::Proxy

  attr_accessor :service

  def initialize(service)
    self.service = service
  end

  def cache_exception(&block)
    yield
  rescue Exception => e
    raise Translate::Service::Error.new(e.message)
  end

  def method_missing(method_sym, *arguments, &block)
    if self.service.respond_to? method_sym
      cache_exception { self.service.send(method_sym, *arguments, &block) }
    else
      super
    end
  end

end

这个Proxy负责统一抛出的错误类型,如果是Net::HTTP请求发生错误 在这里则也会进行一次转换类型。

总结:优秀的程序员,总是能把代码组织的非常漂亮。多学习 多思考 多运用 会让生活变的更美好。

Categories: rails, ruby Tags: