понедельник, 27 мая 2013 г.

puppet not start service

if you define service

service{"logstash":
    enable => true,
    ensure => true
  }

but during execution puppet you receive on service logstash status, and not started
CAUSE is status return 0 instead of 3(for stopped)
simple fix is

status)
     echo -n "$DESC"
     status -p $PID_FILE
+    exit $?
     ;;
   *)


in your init script

четверг, 23 мая 2013 г.

in `expand_path': non-absolute home

in `expand_path': non-absolute home
error can happend in passenger installation process

lib/phusion_passenger/platform_info/ruby.rb:198:in `expand_path': non-absolute home (ArgumentError)


simple fix - define statis path for HOME
export HOME=/tmp

четверг, 9 мая 2013 г.

periodic task on ruboto

For create periodic task on android by ruboto require create handler and assign task with delay in milliseconds (handl.postDelayed(method_for_eecution, 1000)).
And each time when finished  task - assing new(second line in method test_meth)

def onCreate(bundle)
  ....
  handler = Java::android.os.Handler.new
  test_meth(handler)
end

def test_meth(handl)
    toast "test #{Time.now}"
     handl.postDelayed(test_meth(handl), 1000)
end


 And more clear then java code wich was before.


понедельник, 6 мая 2013 г.

vagrant + libvirt + nested virtualization

Уже расписывал как хорош vagrant и как он становится на два порядка лучше с libvirt. Но есть ньюанс - в либвирте столько функций, что плагин для вагранта еще пилить и пилить. Сегодня добавлена одна из самых вкусных - вложенная виртуализация.
Для тех ,кто не в теме: это возможность запускать виртуальные машины внутри виртуальной машины. Я проверял на 3 уровнях вложенности - работает. Хотя больше двух и не надо.
Вся эта магия доступна на процессорах с поддержкой набора команд vmx от интела. Подробности расписаны тут.

Для начала надо включить опцию для модуля kvm_intel

rmmod kvm_intel
mod_probe kvm_intel nested=1


И в опциях vagrant-libvirt добавить libvirt.nested = true
Получится примерно так:

config.vm.provider :libvirt do |libvirt|
    libvirt.driver = "qemu"
    libvirt.host = "example.com"
    libvirt.connect_via_ssh = true
    libvirt.username = "root"
    libvirt.storage_pool_name = "default"
    libvirt.nested = true
  end

Теперь все новые виртуальные машины будут создаваться с поддержкой встроенной виртуализации.
Проверить можно посмотрев опции процессора вирт машины cat /proc/cpuinfo | grep -i vmx
Если нашлось слово vmx - значит можно запускать виртуалку внутри виртулки. Или подключаться использую virt-manager или vagrant c vagrant-libvirt и запускать используя эти инструменты.

воскресенье, 5 мая 2013 г.

Как работал ovirt в 2008 пока его не переписали на мерзкой яве.

Начало использования
Устанавливаем конфиг репозитория ovirt
rpm -ih http://ovirt.org/repos/ovirt/ovirt-release-LATEST.noarch.rpm
Обновляемся используя новый репозиторий
yum update --enablerepo=ovirt -y
либо можно подредактировать конфиг /etc/yum.repos.d/ovirt.repo
и заменить enabled=0 на enabled=1 (теперь всегда по умолчанию он у нас включен)
yum update -y

И ставим необходимые нам пакеты (может занять до 500мб)
yum install --enablerepo=ovirt ovirt-appliance ovirt-docs ovirt-node virt-viewer-plugin qemu-img

и перезапускаем libvirtd
service libvirtd restart
При условии что обородувание поддерживает виртуализацию и подгружен модуль kvm начинаем ставить виртуальный сервер, можно сказать управляющий - все управление происходить будет с него.
Интерфейс которым подключены к локальной сети eth0 - его и укажем
create-ovirt-appliance -e eth0
После этого сделайте
ifdown eth0
ifconfig eth0 /<маска сети> up

Теперь запустим виртуальную машину
virsh start ovirt-appliance

Так же можно понаблюдать за процессом загрузки (при желании даже вмешаться) запустив

virt-viewer ovirt-appliance

Пароль root по умолчанию ovirt.

Адрес панели управления, по умолчанию 192.168.50.2/ovirt
Доступ в панель ovirtadmin/ovirt

Не советую переименовывать hardware pool с именем default. Оказывается что в коде жестко прописано DEFAULT_POOL_NAME = "default". Можете догадаться как я это узнал... конечно переименовал и потом искал в чем ошибка:)

Если хочется покопаться в коде то желательно получить документацию
У меня встретился досадный баг "uninitialized constant RubyToken::AlreadyDefinedToken"
По первому же запросу гугл подсказал что необходимо в файле Rakefile переместить "require 'gettext/utils'" в задачи только нуждающиеся в нем (make_mo и update_po).

Генерируем документы по коду
rake doc:app.

При неудачном завершении работы виртуальной машины на которой крутился ovirt лучше всего - перед загрузкой успеть в меню загрузчика grub
нажать 'e'
выбрать вторую строку и опять 'e'
написать через пробел цифру 1
потом enter и 'b'
таким образом мы загрузимся в singlemode режиме
и запустим проверку диска fsck /dev/sda2
потом просто перезагружаемся /sbin/init 6
должно нормально загрузится

#################редактировать###################
Общение между физическими серверами происходит (как я понял ) по протоколу amqp используя демон qpid.
На добавляемой физической ноде необходимо запустить
ovirt-install-node stateful
также сделал

create-ovirt-appliance -e eth1
затем понял что в сети должны видеть друг друга не только физические ноды но и виртуальная управляющая
потому подключаем ovirtbr0 к локальной сети
сначала brctl addif ovirtbr0 eth0 добавляем интерфейс к мосту
затем ifconfig eth0 down ; ifconfig eth0 0.0.0.0/0 up; что б могли с любых подсетей получать пакеты
так же и на второй ноде
проверив все пингом пытаемся найти в списке необходимые нам физические сервера
################################################

При запуске libvirtd он рассылает multicast dns (224.0.0.251) сообщение о том что запущен libvirt. Ответственный за это демон avahi.

На управляющем сервере в директории рельсов лежит host-browser.rb он слушает на 12120 порту тср запросы с управляемых физических узлов.

На физ узлах есть скрипт /etc/init.d/ovirt ставим аргумент старт и он посылает сообщения на узел с которого грузился

/usr/sbin/ovirt-identify-node отправляет на указаный сервер информацию о узле
после того как он отработает - создается запись
теперь найти как она должна создаваться автоматом

На управляемой ноде в файле /etc/init.d/ovirt-functions определяются основные конфигурационные параметры - в частности порт и сервер управления



Vagrant + libvirt

There are many virtualization technologies.
Sure the best is KVM!!!
But libvirt can  manage different virtualization technologies.

Next step is provide ability test and develop software by many virtual machines.
and vagrant is amazing for it(Thanks Mitchell).

Vagrant's plugin for libvirt 
By this plugin you can test VM localy and remotely(also remotely on many servers).
require only change Vagrantfile


Vagrant.configure("2") do |config|
  config.vm.define :test_vm do |test_vm|
    test_vm.vm.box = "centos64"
  end

  config.vm.provider :libvirt do |libvirt|
    libvirt.driver = "qemu"
    libvirt.host = "example.com"
    libvirt.connect_via_ssh = true
    libvirt.username = "root"
    libvirt.storage_pool_name = "default"
  end
end


Put your ssh public key to remote server and start libvirtd on it.
I use this tools for test multinodes cloud.
Lets together say THANKS to Lukas Stanek

P.S. Virtualbox is crap, and i was happy remove it from my laptop.

суббота, 4 мая 2013 г.

escape string

for bash
$(printf '%q' $1)

For ruby
%q{string!#$%}

firewalld and port forwarding

for forwarding from port 8080 to virtual machine with ip 192.168.122.126


firewall-cmd --zone=public --add-forward-port=port=8080:proto=tcp:toaddr=192.168.122.126

simple client for hornetQ for testing


I like rabbitmq, but for java projects nice choice is hornetq embedded in jboss.
The best way for testing is write code on ruby.
I use library jruby-hornetq


# tested by jruby
require 'rubygems'
require 'hornetq'

connection = HornetQ::Client::Connection.new(:uri => 'hornetq://localhost/')
session = connection.create_session(:username=>'guest',:password=>'secret')


producer = session.create_producer('jms.queue.QeueuName123')
message = session.create_message(HornetQ::Client::Message::TEXT_TYPE,false)
message.body_buffer.write_string('Hello World')
producer.send(message)
session.close
connection.close


java-freek-way is not for me :)

среда, 17 апреля 2013 г.

autoexpect

Expect - tool for automatically run interactive scripts.
Autoexpect - tool for generate expect script.
Generated code is dirty, but working, It will save many hours.
Example:

autoexpect ssh root@192.168.122.240


work with script, after logout you receive script.exp which contain

 set timeout -1
spawn ssh root@192.168.122.240
match_max 100000
expect -exact "Warning: Permanently added '192.168.122.240' (RSA) to the list of known hosts.\r\r
root@192.168.122.240's password: "
send -- "testpass\r"
expect -exact "\r
Permission denied, please try again.\r\r
root@192.168.122.240's password: "
send -- "vagrant\r"
expect -exact "\r
Last login: Mon Mar 25 21:38:15 2013\r\r
^[\]0;root@centos64:~^G^[\[?1034h\[root@centos64 ~\]# "
send -- "uname -a\r"
expect -exact "uname -a\r
Linux centos64.vagrantup.com 2.6.32-358.el6.x86_64 #1 SMP Fri Feb 22 00:31:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux\r
^[\]0;root@centos64:~^G\[root@centos64 ~\]# "
send -- "touch /tmp/123\r"
expect -exact "touch /tmp/123\r
^[\]0;root@centos64:~^G\[root@centos64 ~\]# "
send -- "exit\r"
expect eof

воскресенье, 14 апреля 2013 г.

pre-commit hooks for checking commits

there are examples for ruby code and puppet manifests(chef can validate automatically, but stupid puppet can't):
1. create file ./.git/hooks/pre-commit
2. add code

#!/bin/sh
echo 'working pre commit hook'
git diff --cached --name-only --diff-filter=ACM | while read file; do
  # check only puppet files
  if [ "${file##*.}" == 'pp' ]
  then
    echo "check $file"
    puppet parser validate $file
  fi
done

3. require set exec permissions. DO NOT FORGET !!!! (it is cause for not execution hook)
chmod +x ./.git/hooks/pre-commit
Complete.

Also example for ruby:

#!/bin/sh
echo 'working pre commit hook'
git diff --cached --name-only --diff-filter=ACM | while read file; do
  if [ "${file##*.}" == 'rb' ]
  then
    echo "check rubocop $file"
    rubocop $file
  fi
done

воскресенье, 7 апреля 2013 г.

shmmax error for start postgresql

During start postgresql appear error  
Apr 07 12:38:55 localhost.localdomain pg_ctl[9810]: FATAL: could not create shared memory segment: Invalid argument 
Apr 07 12:38:55 localhost.localdomain pg_ctl[9810]: DETAIL: Failed system call was shmget(key=5432001, size=41279488, 03600). 
Apr 07 12:38:55 localhost.localdomain pg_ctl[9810]: HINT: This error usually means that PostgreSQL's request for a shared memory segment exceeded your ker...nections. 
Apr 07 12:38:55 localhost.localdomain pg_ctl[9810]: If the request size is already small, it's possible that it is less than your kernel's SHMMIN parameter...lled for. 
Apr 07 12:38:55 localhost.localdomain pg_ctl[9810]: The PostgreSQL documentation contains more information about shared memory configuration. 
Apr 07 12:39:00 localhost.localdomain pg_ctl[9810]: pg_ctl: could not start server Apr 07 12:39:00 localhost.localdomain pg_ctl[9810]: Examine the log output.

fix in chef recipes

shmmax='kernel.shmmax=335544320' 
execute "set shmax" do
 command "sysctl -w #{shmmax}" 
end 

file "/etc/sysctl.d/shmmax.conf" do
 content shmmax 
end

среда, 16 мая 2012 г.

Custom vagrant image

1, start virtualbox and install your os
2. install ruby and chef
3, install http://download.virtualbox.org/virtualbox/4.2.6/VBoxGuestAdditions_4.2.6.iso
mount -o loop ./VBoxGuestAdditions_4.2.6.iso /mnt
run /mnt/VBoxLinuxAdditions.run --nox11
4. create user vagrant
5. download key https://github.com/mitchellh/vagrant/tree/master/keys/ and set to /home/vagrant/.ssh/authorized_keys
Also recheck permissions and selinux (chown -R vagrant:vagrant /home/vagrant/.ssh && chmod 700 /home/vagrant/.ssh && chmod 600 /home/vagrant/.ssh/authorized_keys && restorecon -R /home/vagrant/.ssh)
6. configure /etc/sudoers (comment Defaults requiretty and add vagrant as sudo user without password vagrant ALL=(ALL) NOPASSWD: ALL)
7. enable ssh
8. logout and poweroff guest vm
9. run vagrant package --base g2012 package.box
10. run vagrant box add g3 ./package.box
11. set g3 to your Vagrantfile to
config.vm.box = "g3"

среда, 1 февраля 2012 г.

rabbitmq и ha для очереди

Rabbitmq передает сообщения. И сообщения частенько очень важные.
Что б не терять их, при отказе железки, можно использовать rabbitmq cluster.
Но есть один ньюанс - в кластере, по умолчанию, очередь хранится на одной ноде.
Добавляем в опции очереди x-ha-policy => all и теперь копии очереди есть на всех нодах и если одна упадет , сообщения не потеряются.
Клиентская программа должна знать куда переподключаться в случае падения и использовать подтверждение о получении сообщения.

суббота, 28 января 2012 г.

deploy spree to openshift

Instruction how to deploy spreecommerce to openshift
work with ruby 1.8.7 because openshift work with this version.
ruby 1.9. hash syntax will create problem in openshift cloud

1. create application on openshift
rhc-create-app -a spree -t rack-1.1
Создалось приложение в облаке редхата и папочка spree с простым rack приложением.
А нам надо создать rails приложение с гемами spree.
rm -f ./spree/README
rails new ./spree -d postgresql -f
Обратите внимание - используем постгрес(дело вкуса конечно,но все ж знают, что постгрес вкуснее)
2. add database(postgresql)
rhc-ctl-app -a spree -e add-postgresql-8.4
Если понадобится удалить подключенную базу
rhc-ctl-app -a spree -e remove-postgresql-8.4
По завершению мы получим данные для подключения к базе.
Их стоит записать в spree/config/database.yml
и не забудьте добавить поле host и вписать ip из подобной строки Connection URL: postgresql://127.1.13.1:5432
И настроить базу для development режима
development:
  adapter: sqlite3
  database: db/dev.sqlite3

И в Gemfile добавляем гем sqlite3 для группы development
теперь перемещаемся в папку spree
bundle install && bundle exec rails g spree:install
добавляем сприи в Gemfile
echo "gem 'spree', :git => 'git://github.com/spree/spree.git'" >> ./Gemfile
Gemfile.lock должен быть актуальным
bundle install
mkdir public/images && cp public/favicon.ico public/images/favicon.ico
RAILS_ENV=development bundle exec rake assets:precompile

добавить код в .openshift/action_hooks/deploy

pushd ${OPENSHIFT_REPO_DIR} > /dev/null
RAILS_ENV=production bundle exec rake db:migrate -y
RAILS_ENV=production bundle exec rake db:seed -y
popd > /dev/null


и теперь пушим git push
после удачного деплоя очищаем .openshift/action_hooks/deploy

first request will broken - it is problem on timeout parameter in proxy server.
but exist problem with timeout

P.S.
after few updates require use this database.yml


adapter: <%=ENV['OPENSHIFT_DB_TYPE']%>
encoding: utf8
host: <%=ENV['OPENSHIFT_DB_HOST']%>
port: <%=ENV['OPENSHIFT_DB_PORT']%>
socket: <%=ENV['OPENSHIFT_DB_SOCKET']%>
database: <%=ENV['OPENSHIFT_APP_NAME']%>
username: <%=ENV['OPENSHIFT_DB_USERNAME']%>
password: <%=ENV['OPENSHIFT_DB_PASSWORD']%>

воскресенье, 14 августа 2011 г.

Кеширование в мультидоменном веб приложении

добавляем в контроллер

before_filter { |c|
   c.class.page_cache_directory = "#{RAILS_ROOT}/public/#{c.request.host}"
}

в логах сразу видим как пишется

Write fragment views/sub.domain.com/s/test (2.6ms)

и при повторном запросе

Read fragment views/sub.domain.com/s/test (0.9ms)

Итого: с 300мс до 10 мс рендеринг страницы.

среда, 3 августа 2011 г.

Получение в SproutCore нескольких массивов данных одним запросом к бакэнду.

Получение нескольких массивов данных одним запросом к бакэнду.

Допустим, у нас есть приложение Blog, в котором есть модели Blog.Post и Blog.Quote. Пусть они выводятся сервером по адресу '/records.json' и в json выглядят вот так:
{posts: [{post1}, {post2}, {post3}], quotes: [{quote1}, {quote2}, {quote3}]}
Что бы уменьшить количество запросов к серверу и тем самым увеличить скорость получения данных, нам нужно немного изменить datasource приложения.
Шаг 1. Создать запрос:
Blog.QUERY_POSTS_AND_QUOTES = SC.Query.local([Blog.Post, Blog.Quote]);
В SC.Query.local можно передавать не только один тип записи, но и массив типов.
Шаг 2. Создать хэш-таблицу с ссылками на данные и типами записей:
Это шаг нужен что бы избежать огромного количества if в функции fetch()

Blog.Datasource = SC.DataSource.extend({
   urls: {
     posts_and_quotes: { url: '/records.json', records: ['posts', 'quotes'] }
   },
});

Так же нам нужно поправить шан запрос, установив ему атрибум id, соответствующий имени одного из элементов urls, в данном случае posts_and_quotes:
Blog.QUERY_POSTS_AND_QUOTES = SC.Query.local([Blog.Post,Blog.Quote]).set('id','posts_and_quotes');
Шаг 3. Пишем fetch():

fetch: function(store, query) {
   //Получаем id запроса и берём из urls ссылку для запроса в соответствии с этим id
   var id = query.get('id');
   //Если id не задан, значит запрос не должен обращаться к серверу
   if(!id) return NO;
   var url = this.urls[id]['url'],
     funcs = this.get('fetchDidComplete'),
     //Если нужна особая обработка какого нибудь запроса то в fetchDidComplete
     //нужно добавить функцию, имя которой совпадает с id (ещё одна хэш-таблица).
     //Если имя не указано, то по завершении запроса будет вызвана default функция

     func = funcs[id] || funcs['default'];
   SC.Request.getUrl(url).json().notify(this, func, store, query).send();
   return YES;
}



Шаг 4. Обрабатываем полученные данные:

fetchDidComplete: {
   'default': function(response, store, query) {
     if (SC.ok(response)) {
       //В зависимости от id берём нужные записи из полученного json
       var body = this.urls[query.get('id')]['records'];
       //Получаем тип записи
       var recordType = query.get('recordType');
       //Если тип не задан, значит их несколько и они хранятся в recordsTypes
       if (!recordType) {
       var recordTypes = query.get('recordTypes'); //Получаем типы записей
       jQuery.each(body, function(i) {
       //Загружаем в store записи разных типов. Порядок выдачи записей разных типов сервером
       //и порядок этих типов в запросе должны совпадать. Т.е.:
       //SC.Query.local[Scm.Product, Scm.Taxon] и {products: [{product1}, {product2}], taxons: [{taxon1}, {taxon2}]}

       store.loadRecords(recordTypes[i], response.get('body')[body[i]]); });
     }
     else {
       store.loadRecords(recordType, response.get('body'));
     }
     store.dataSourceDidFetchQuery(query);
     } else store.dataSourceDidErrorQuery(query, response);
   }
}


Шаг 5. Используем новый запрос в приложении:
var data = Blog.store.find(Blog.QUERY_POSTS_AND_QUOTES);
Теперь, что бы получить отдельно posts, а отдельно quotes используем scoped queries:

var posts = data.find(SC.Query.local(Blog.Post);
var quotes = data.find(SC.Query.local(Blog.Quote);

Ну и теперь можно заполнить ArrayController'ы приложения полученными данными:

Blog.postsController.set('content', posts);
Blog.quotesController.set('content', quotes);

Полностью datasource будет выглядеть так:
Blog.Datasource = SC.DataSource.extend({
urls: {
   posts_and_quotes: { url: '/records.json', records: ['posts', 'quotes'] }
},
fetch: function(store, query) {
   //Получаем id запроса и берём из urls ссылку для запроса в соответствии с этим id
   var id = query.get('id');
   //Если id не задан, значит запрос не должен обращаться к серверу
   if(!id) return NO;
   var url = this.urls[id]['url'],
     funcs = this.get('fetchDidComplete'),
     //Если нужна особая обработка какого нибудь запроса то в fetchDidComplete
     //нужно добавить функцию, имя которой совпадает с id (ещё одна хэш-таблица).
     //Если имя не указано, то по завершении запроса будет вызвана default функция
     func = funcs[id] || funcs['default'];
   SC.Request.getUrl(url).json().notify(this, func, store, query).send();
   return YES;
},
fetchDidComplete: {
   'default': function(response, store, query) {
   if (SC.ok(response)) {
     //В зависимости от id берём нужные записи из полученного json
     var body = this.urls[query.get('id')]['records'];
     //Получаем тип записи
     var recordType = query.get('recordType');
     //Если тип не задан, значит их несколько и они хранятся в recordsTypes
     if (!recordType) {
       var recordTypes = query.get('recordTypes'); //Получаем типы записей
       jQuery.each(body, function(i) {
       //Загружаем в store записи разных типов. Порядок выдачи записей разных типов сервером
       //и порядок этих типов в запросе должны совпадать. Т.е.:
       //SC.Query.local[Scm.Product, Scm.Taxon] и {products: [{product1}, {product2}], taxons: [{taxon1}, {taxon2}]}
       store.loadRecords(recordTypes[i], response.get('body')[body[i]]); });
     }
     else {
       store.loadRecords(recordType, response.get('body'));
     }
     store.dataSourceDidFetchQuery(query);
     } else store.dataSourceDidErrorQuery(query, response);
     }
   },
});

вторник, 2 августа 2011 г.

Tradefast & Sproutcore 1.6: Создание и использование тем

Tradefast & Sproutcore 1.6: Создание и использование тем
В этом небольшом руководстве описывается процесс создания и последующего использования своей темы для sproutcore-приложения, импользующего handlebars в качестве шаблонизатора.

В самом простом (и наиболее часто используемом) случае, тема - это набор css-стилей. Помимо этого темы могут заменять DOM, сгенерированный через views приложения.

Создадим новую тему командой sc-gen theme и назовём её tradefast-red:

sc-gen theme tradefast-red
~ Created directory at themes/tradefast_red
~ Created directory at themes/tradefast_red/resources
~ Created file at themes/tradefast_red/resources/theme_styles.css
~ Created file at themes/tradefast_red/theme.js
~ Created file at themes/tradefast_red/Buildfile
Your theme is now ready to use!


Sproutcore добавил в /themes (если этой папки нет, то она так же будет сгенерирована) папку /tradefast_red, в которой хранятся все необходимые для темы файлы. В main.js определяется новая тема и добавляется в приложение:

TradefastRed = SC.AceTheme.create({
name: 'tradefast-red'
});
SC.Theme.addTheme(TradefastRed);


По-умолчанию новая тема создаётся как под-тема темы Ace, которая не нужна, если приложение использует handlebars. Поэтому лучше удалить ‘Ace’ из определения темы:
TradefastRed = SC.Theme.create

Так же стоит убрать ace из tradefast_red/Buildfile:
Было: config :tradefast_red, :css_theme => 'ace.tradefast-red'
Стало: config :tradefast_red, :css_theme => 'tradefast-red'

В папке /resources находятся стили вашей темы, по-умолчанию это файл theme_style.css, но вы можете добавлять сколько угодно css-файлов. В этой же папке стоит хранить все изображения, связанные с темой.

Что бы использовать тему в приложении, нужно указать её в Buildfile самого приложения, который лежит на одном уровне с папками /themes и /apps:
config :all, :required => :sproutcore', :theme => "tradefast_red"
Обратите внимание, что имя темы совпадает с именем папки с темой в /themes/. Не перепутайте с именем, указанном в main.js. :theme => “tradefast-red” не сработает.

Остаётся только перезапустить сервер sc-server и посмотреть на новую тему в действии.

Внимание: не рекомендуется при использовании тем создавать css внутри самого приложения, так как эти стили определяются до темы и переписывают все правила, заданные в вашей теме. Вместо того что бы портить css кучей !important, лучше хранить полный css в каждой теме отдельно. Такой подход так же позволит переопределять макет приложения без лишних телодвижений.

четверг, 14 июля 2011 г.

latest xen 4 and libvirt.

For connect libvirt to xen4 on fedora15 require install latest version of libvirt.
Today it is
rpm -Uvh http://kojipkgs.fedoraproject.org/packages/libvirt/0.9.3/2.fc16/x86_64/libvirt-0.9.3-2.fc16.x86_64.rpm http://kojipkgs.fedoraproject.org/packages/libvirt/0.9.3/2.fc16/x86_64/libvirt-python-0.9.3-2.fc16.x86_64.rpm http://kojipkgs.fedoraproject.org/packages/libvirt/0.9.3/2.fc16/x86_64/libvirt-client-0.9.3-2.fc16.x86_64.rpm http://kojipkgs.fedoraproject.org/packages/parted/3.0/2.fc16/x86_64/parted-3.0-2.fc16.x86_64.rpm http://kojipkgs.fedoraproject.org/packages/netcf/0.1.8/1.fc16/x86_64/netcf-libs-0.1.8-1.fc16.x86_64.rpm

But after tests: kvm is faster simpler and better.

воскресенье, 10 июля 2011 г.

capybara get html

For get html
find("ul.random_quotes").native.to_html
for get elements count
find("ul.random_quotes").native.search("li").size