Михаил Овчинников

Восстанавливаем файлы, удаленные в прошлых коммитах в Git

Git Bash

Сегодня передо мной встала довольно простая, но интересная задача: восстановить несколько файлов в репозитории Git, которые были удалены некоторое время назад в разных коммитах. Задача простая, потому что решение легко найти в соотвествующих ответах на Stack Overflow. Мне лишь осталось слегка адаптировать приведенные примеры команд для своих нужд.

Я не помнил точные названия файлов и уж тем более не знал хэши коммитов, в которых производилось удаление. Поэтому воспользовался сниппетом от пользователя Robert Munteanu, чтобы вывести историю удаленных файлов:

git log --diff-filter=D --summary

Отыскав необходимые файлы и коммиты, можно было бы воспользоваться простым git checkout для восстановления, но список был весьма велик, так что пришлось набросать небольшой скрипт на Bash.

#!/bin/bash

set -o nounset 
set -o errexit

declare -a files=(
    "source/posts/2012-11-11-twitter/Untitled.png"
    "source/posts/2013-06-08-wb/unnamed.png"
    "source/posts/2012-10-13-lift/IMG_0020.png"
);

counter=0
while [ $counter -lt ${#files[@]} ]; do
    file=${files[$counter]}
    commit=$(git rev-list -n 1 HEAD -- "$file") 
    echo Restoring file: $file from commit: $commit
    git checkout $commit^ "$file" 
    let counter+=1
done

В скрипте я объявляю массив с нужными мне файлами (в примере я сократил список). Далее в цикле проходимся по этому списку, при помощи команды git rev-list -n 1 HEAD -- "$file" находим коммит, в котором последний раз использовался этот файл и при помощи git checkout $commit^ "$file" восстанавливаем его из предыдущего коммита (для этого используется символ ^).

Модули Metasploit

Linux Metasploit Безопасность Журнал Хакер Ruby

Эта статья была впервые опубликована в журнале “Хакер”, здесь публикуется исходная версия, до отправки в редакцию. Вся информация предоставлена исключительно в ознакомительных целях. Ни редакция, ни автор не несут ответственности за любой возможный вред, причиненный материалами данной статьи.

Счет встроенных модулей в Metasploit перешел на тысячи, но, рано или поздно, любой, кто плотно работает с фреймворком, сталкивается с необходимостью расширить его функционал собственными эксплойтами и вспомогательными модулями. Сегодня мы рассмотрим все необходимые аспекты создания модуля с нуля, а также особенности языка Ruby, которые нужно учитывать при написании.

Организация файлов в MSF

Прежде чем приступать к написанию своего модуля, необходимо разобраться с существующей структурой файлов в фреймоворке и механизм поиска модулей. Файлы Metasploit располагаются в 2-х основных локациях.

Первая - это директория, куда был установлен фреймворк. Например, в Kali Linux это: /usr/share/metasploit-framework. В папке lib, помимо прочего, мы можем обнаружить библиотеку Rex, которая предоставляет базовые методы для работы с файлами и протоколами. Основа фреймворка: библиотеки Core и Base, располагаются в директории lib/msf. Практикующим основательный подход, изучение исходных кодов можно начать с класса Module из lib/msf/core, который определяет базовое поведение модулей. От него, в свою очередь, наследуются классы, которые определяют тип модуля Auxiliary, Exploit, Payload и т.п (их можно найти там же). Модули, идущие в поставке с фреймворком, можно обнаружить в директории modules, где они разбиты по типам.

Вторая локация - директория .msf4 в домашней папке пользователя. Именно она рекомендуется авторами фреймворка в качестве основного хранилища всех внешних модулей. Её структура должна быть аналогична упомянутой выше папке modules. Например, если ты скачал эксплоит от внешнего разработчика, или написал его сам, то чтобы MSF распознал его, он должен находиться по пути ~/.msf4/modules/exploits. Внутри этой локации рекомендуется сортировать модули по подпапкам, например по операционным систем - MSF распознает их. Например, путь ~/.msf4/modules/exploits/windows/module_name будет валиден с точки зрения фреймворка.

Архитектура модуля

Предлагаю рассмотреть базовый шаблон модуля, который не будет производить полезного действия, но будет корректно распознаваться MSF.

Подключим библиотеки, сосавляющие ядро фреймворка, которые располагаются в msf/core при помощи ключевого слова require.

require 'msf/core'

Далее необходимо отнаследоваться от класса, который определит тип модуля. В нашем случае это будет Auxiliary.

class Metasploit3 < Msf::Auxiliary

Название класса “Metasploit3” определяет версию фреймворка для которого пишется модуль.

Определим метод initialize, который выполняет роль конструктора класса в Ruby.

def initialize
  super(
    'Name' => 'Hello world Module',
    'Description' => 'Useless module for education purposes',
    'Author' => 'Xakep',
    'License' => MSF_LICENSE
  )
end

Ключевое слово super используется в Ruby при наследовании, когда не требуется полностью переопределять метод, а необходимо лишь дополнить его поведение. Происходит вызов метода с таким же именем в родительском классе, и ему передаются необходимые параметры. В данном случае, будет вызван метод initialize родительского класса Auxiliary, а в качестве параметров ему будет передан хэш (пары ключ-значение) с метаданными: название модуля, его описание, автор и лицензия.

Следующее, что потребуется определить - это непосредственно сам метод, который будет выполнять какое-либо полезное действие. В нашем случае он будет выводить строку c приветствием. Естественно, в реальных модулях методов будет гораздо больше, в чем ты сможешь убедиться исследовав встроенные модули MSF. Название метода должно быть run.

def run
  puts 'Hello from MSF module!'
end

Приведу полный код нашего первого модуля:

require 'msf/core'

class Metasploit3 < Msf::Auxiliary
  def initialize
    super(
      'Name' => 'Hello world Module',
      'Description' => 'Useless module for education purposes',
      'Author' => 'Xakep',
      'License' => MSF_LICENSE
    )
  end

  def run
    puts 'Hello from MSF module!'
  end
end

Сохраняем его в директорию ~/.msf4/modules/auxiliary/xmodules в файл под названием “hello.rb”. Теперь запускаем консоль Metasploit (командой msfconsole). После загрузки консоли, можно обратить внимание, что число auxiliary-модулей увеличилось на один.

Если этого не произошло и модуль по причине ошибки не был загружен, то увидеть сообщение об этом можно выше вместе с остальной загрузочной инфомацией.

Сообщение об ошибке при загрузке модуля

Мы можем найти наш модуль по слову “hello”, либо сразу выбрать его для работы:

use auxiliary/xmodules/hello

Как можно заметить, команде use мы передаем структуру, которая повторяет путь к файлу (начиная от директории “modules”), без расширения. Осталось только запустить модуль командой run и увидеть сообщение, которое мы указали в одноименном методе.

Результат запуска нашего простейшего модуля

Простой модуль для работы с SSH

Рассмотренного выше минимального примера должно быть достаточно, чтобы понять, что из себя представляют модули и как с ними работает Metasploit. Однако, необходимо раскрыть дополнительно несколько важных особенностей и для этого мы напишем более практический пример.

Предлагаю решить следующую задачу: дан список IP-адресов, написать auxiliary-модуль, который определит доступен ли этот сервер по SSH, и, если доступен, определить доступные типы авторизации.

Помимо образовательных целей, такой модуль будет полезен и для простого админа, и для пентестера: получив список хостов каждого типа, можно будет натравить на них один из соотвествующих встроенных модулей уже с целью проверки на стойкость используемого пароля или ключа.

Подключим необходимые библиотеки.

require 'msf/core'
require 'net/ssh'
require 'stringio'
require 'logger'

Отметим, что подключается модуль Scanner, который содержит готовые методы для соотвествующих операций.

class Metasploit3 < Msf::Auxiliary
  include Msf::Auxiliary::Scanner

Здесь нужно понять механизм примесей (mixin), который довольно активно используется при написании модулей. В контексте Ruby также существует понятие модуля - это способ организации методов, классов и констант, который может использоваться, как аналог пространств имен в других языках (namespaces), либо для реализации своего рода множественного наследования, которое и получило название mixin. Для его реализации необходимо подключить библиотеку, содержащую модуль (в данном случае он является частью msf/core), а затем в нужном месте подключить модуль при помощи ключевого слова include. Так класс нашего модуля унаследует все методы базового модуля Scanner.

Код метода initialize будет уже знакомым.

def initialize
  super(
    'Name' => 'SSH Auth type checker',
    'Description' => 'Check host availability by SSH and detect auth type',
    'Author' => 'Xakep',
    'License' => MSF_LICENSE
  )

  register_options(
    [
      Opt::RPORT(22)
    ], self.class
  )
end

Можно заметить, что здесь я зарегистрировал опцию RPORT. Это те самые опции, которые выставляются при помощи команды set в консоли Metasploit. Кстати, если ты посмотришь информацию о модуле командой info, то увидишь и другие опции: они зарегистрировались модулем Scanner, который я упоминал выше.

Опции, доступные нашему модулю

Метод run также реализован в Scanner, и, в данном случае, нет смысла его переопределять. Зато этот модуль предоставляет нам более удобный метод под названием run_host, которому передается IP-адрес. Этот код будет выполняться для каждого хоста.

  def run_host(ip)
    debug_info = StringIO.new
    log = Logger.new debug_info

    opts_hash = {
      port: datastore['RPORT'],
      verbose: Logger::DEBUG,
      logger: log,
      timeout: 5
   }

  begin
    Net::SSH.start(ip, 'user', opts_hash) do
      method = extract_succeded_method(debug_info.string)
      print_good("#{ip} - connection established, auth method: #{method}")
    end
  rescue Net::SSH::AuthenticationFailed
    methods = extract_auth_methods(debug_info.string)
    print_debug("#{ip} - auth failed, available methods: #{methods}")
  rescue Timeout::Error, Errno::ECONNREFUSED, Rex::ConnectionRefused
    print_error("#{ip} - host doesn't respond")
  end
end

В нем мы сначала определяем переменные служебного характера, они требуются для того чтобы лог подключения писался в переменную, а не выводился на консоль. Затем определяется хэш с опциями. В нем мы указываем, что порт мы берем из опции RPORT, которую определили в методе initialize, далее выставляем “многословность” логгирования в режим Debug, чтобы получить интересующую нас информацию, определяем какому иэкземпляру объекта Logger отдавать лог и последним параметром идет таймаут подключения.

Теперь мы при помощи модуля Net::SSH (мы подключали его в начале, он входит в состав MSF) запускаем сессию, передав ей IP-адрес хоста, имя пользователя (в данном случае оно неважно поэтому я поставил просто ‘user’) и хэш с настройками. Далее все просто: если вдруг удалось подключиться и авторизоваться, то выводим соотвествующее сообщение, где вытягиваем из лога метод, которым было авторизовано соединение. Если авторизация провалилась (что в данном случае ожидаемый исход), то мы достанем из лога доступные методы авторизации для данного хоста. Если же хост недоступен по разным причинам, то напечатаем соотвествующее сообщение. Обрати внимание на специальные методы для вывода информации на консоль MSF: print_good, print_debug и print_error. Они нужны чтобы подсвечивать результаты соотвествующими символами, для более легкого чтения.

Для получения информации из лога я написал два вспомогательных метода, которые достают при помощи регулярных выражений нужные строчки (далеко не самый оптимальный вариант, здесь используется для простоты).

def extract_auth_methods(debug_info)
  debug_info
    .match(/allowed\smethods:\s(.+)/)
    .captures
    .first
end

def extract_succeded_method(debug_info)
  debug_info
    .match(/(.+)\ssucceeded/)
    .captures
    .first
end

Привожу полный код модуля:

require 'msf/core'
require 'net/ssh'
require 'stringio'
require 'logger'

class Metasploit3 < Msf::Auxiliary
  include Msf::Auxiliary::Scanner

  def initialize
    super(
      'Name' => 'SSH Auth type checker',
      'Description' => 'Check host availability by SSH and detect auth type',
      'Author' => 'Xakep',
      'License' => MSF_LICENSE
    )

    register_options(
      [
        Opt::RPORT(22)
      ], self.class
    )
  end

  def run_host(ip)
    debug_info = StringIO.new
    log = Logger.new debug_info

    opts_hash = {
      port: datastore['RPORT'],
      verbose: Logger::DEBUG,
      logger: log,
      timeout: 5
    }

    begin
      Net::SSH.start(ip, 'user', opts_hash) do
        method = extract_succeded_method(debug_info.string)
        print_good("#{ip} - connection established, auth method: #{method}")
      end
    rescue Net::SSH::AuthenticationFailed
      methods = extract_auth_methods(debug_info.string)
      print_debug("#{ip} - auth failed, available methods: #{methods}")
    rescue Timeout::Error, Errno::ECONNREFUSED, Rex::ConnectionRefused
      print_error("#{ip} - host doesn't respond")
    end
  end

  def extract_auth_methods(debug_info)
    debug_info
      .match(/allowed\smethods:\s(.+)/)
      .captures
      .first
  end

  def extract_succeded_method(debug_info)
    debug_info
      .match(/(.+)\ssucceeded/)
      .captures
      .first
  end
end

Теперь осталось только выбрать модуль в консоли MSF, указать адреса хостов через установку опции RHOSTS, запустить модуль и увидеть результат.

Результат выполнения нашего модуля

Домашнее задание

Сейчас наш модуль выводит информацию только в консоль, что может быть не совсем удобным для дальнейших исследований. Предлагаю тебе самостоятельно изучить документацию модуля Msf::Auxiliary::Report и прикрутить к этому примеру логгирование в базу и/или в файл.

Итог

Мы рассмотрели много особеностей модулей MSF предлагаю для окончательного закрепления пробежаться по основным этапам написания модуля:

  • Подключаем необходимые библиотеки при помощи ключевого слова require. При построении модулей можно (и нужно) использовать библиотеки которые располагаются в директории lib. Прежде всего это Rex и Core, в которых реализовано множество готового функционала;
  • Объявляем класс, который наследуется от базового класса соотвествующего типу модуля, в зависимости от желаемого поведения модуля;
  • В Ruby нет множественного наследования, зато есть механизм примесей, который позволит тебе подключать нужные модули при помощи ключевого слова include после объявления класса;
  • Определяем методы:
    • initialize - в него вносим информацию о модуле и определяем опции;
    • Методы, выполняющие полезное действие, в зависимости от типа модуля и нужд.

Cсылки

Погружение в Metasploit

Linux Metasploit Безопасность Журнал Хакер

Эта статья была впервые опубликована в журнале “Хакер”, здесь публикуется исходная версия, до отправки в редакцию. Вся информация предоставлена исключительно в ознакомительных целях. Ни редакция, ни автор не несут ответственности за любой возможный вред, причиненный материалами данной статьи.

Говоря об анализе информационной безопасности сложно не упомянуть Metasploit. Мощный, открытый инструмент с продуманной архитектурой, сотнями контрибьюторов, включающий в себя тысячи модулей, обеспечивающих автоматизацию эксплуатации огромного количества уязвимостей. При этом оставаясь простым в использвании, он позволяет проводить аудиты не только профессиональным пентестерам, но и любому разработчику или администратору, обеспокоенным уровнем безопасности своего проекта.

Предыстория

История Metasploit берет начало в 2003 году. HD Moore, работая пентестером в небольшой консалтинговой компании, замечает ряд неудобств в организации хранения и использования средств анализа безопасности. На тот момент, это был просто набор разрозненных эксплойтов и скриптов, общая информация о которых хранилась в базе данных. Информация о необходимом окружении для запуска скриптов как правило отсутствовала. Также они несли в себе множество устаревшего кода, требовали модификации жестко прописанных путей для каждого конкретного случая и т.п., что весьма затрудняло рабочий процесс и усложняло разработку новых инструментов.

В Metasploit автор, пытаясь решить эту проблему, создает консольную утилиту на Perl с псевдографическим интерфейсом и включает в неё порядка 11 эксплоитов. Сообщество встретило первую версию Metasploit весьма холодно, изрядно критикуя, как архитектуру, так и саму идею. Тем не менее, HD Moore не сдается и даже находит сподвижника в лице spoonm, с которым они доводят до ума модульную архитектуру фреймворка и выпускают вторую версию в 2004 году. Со временем фреймворк начинает набирать популярность и обретать новых контрибьюторов.

Следующим значимым шагом был перевод Metasploit c Perl на Ruby, для того чтобы избежать ограничений Perl, обеспечить кроссплатформенность и добиться большей гибкости при разработке. В 2009 году фреймворк приобретает компания Rapid7, под эгидой которой продолжилось развитие opensource-версии, а также стали появляться коммерческие версии продукта. Сам фреймворк давно перерос статус простого набора для пентестера и сегодня можно его можно встретить (хотя и нечасто) даже в арсенале “мирных” системных администраторов и программистов.

Версии

На момент написания статьи Metasploit распространяется в 4-х версиях:

  • Framework - базовая версия с консольным интерфейсом;
  • Community - бесплатная версия, включающая дополнительно веб-интерфейс и часть функционала из коммерческих версий;
  • Express - для коммерческих пользователей, включает функционал позволяющий упростить проведение базовых аудитов и формирование отчетности по ним;
  • Pro - самая продвинутая версия, предоставляет расширенные возможности для проведения атак, позволяет формировать цепочки задач для аудита, составлять подробную отчетность и многое другое.

Помимо веб-интерфейса, доступного в версиях Community, Express и Pro, существуют такие проекты, как Armitage и Cobalt strike, предоставляющие GUI-интерфейс для фреймворка.

Установка

На текущий момент поддерживаются все актуальные версии Windows и большинство популярных дистрибутивов Linux. В обоих случаях разработчики предоставляют графический инсталлятор, так что проблем с установкой возникнуть не должно. Специализированные дистрибутивы для пентеста, такие как Kali Linux, Pentoo, Black Arch и некоторые другие уже включают Metasploit в свой состав.

Стоит отметить, что необходимо перед установкой выключить антивирусы и другие средства защиты, т.к. большинство из них распознают Metasploit, как вредоносную программу.

База данных

Еще один момент, который стоит учесть - это использование фреймворком базы данных для хранения информации о хостах, сервисах, уязвимостях и прочем. Наличие подключения к базе не является обязательным условием для функционирования фреймворка, тем не менее многие предпочтут использовать этот функционал, для удобства и повышения производительности.

Metasploit использует PostgreSQL, поэтому тебе понадобится установить её на свою систему. Затем убедиться, что запущены соотвествующие сервисы БД и фреймворка. Запустить их можно соотвествующими командами (команды приводятся для Kali Linux, могут отличаться в твоем дистрибутиве):

service postgresql start
service metasploit start

Далее проверим, что фреймворк успешно установил подключение. Откроем консоль Metasploit командой msfconsole, а затем выполним db_status, в ответ на которую система должна вернуть что соединение с базой установлено.

Структура фреймворка

Структура фреймворка

Сердцем Metasploit является библиотека Rex. Она требуется для операций общего назначения: работа с сокетами, протоколами, форматирование текста, работа с кодировками и т.п. На ней базируется библиотека MSF Core, которая предоставляет базовый функционал и “низкоуровневое” API. Его использует библиотека MSF Base, которая в свою очередь предоставляет API для плагинов, интерфейса пользователя (как консольного, так и графического), а также модулей.

На модулях стоит остановиться подробнее. Они делятся на несколько типов, в зависимости от предоставляемой функциональности:

  • Exploit - код эксплуатирующий определенную уязвимость на целевой системе (например, переполнение буфера);
  • Payload - код, который запускается на целевой системе после того, как отработал эксплоит (устанавливает соединение, выполняет шелл-скрипт и т.п.);
  • Post - код, который который запускается на системе после успешного проникновения (собирает пароли, скачивает файлы и т.п.);
  • **Encoder **- инструменты для обфускации модулей с целью избежать обнаружения антивирусами;
  • NOP - генераторы NOP’ов. Это ассемблерная инструкция, которая не производит никаких действий. Используется чтобы заполнять пустоту в исполняемых файлах, для подгонки под необходимый размер;
  • Auxiliary - модули для сканирования сети, анализа трафика, и т.д.

Команды msfconsole

Не смотря на наличие графических интерфейсов, самым распространенным способом работы с Metasploit по прежнему остается консольный интерфейс msfconsole. Рассмотрим основные команды:

  • use - выбрать определенный модуль для работы с ним;
  • back - операция обратная use: перестать работать с выбранным модулем и вернуться назад;
  • show - вывести список модулей определенного типа;
  • set- установить значение определенному объекту;
  • run - запустить вспомогательный модуль после того, как были установлены необходимые опции;
  • info - вывести информацию о модуле;
  • search - найти определенный модуль;
  • check - проверить подвержена ли целевая система уязвимости;
  • sessions - вывести список доступных сессий.

Пентест Wordpress

Вооружившись полученными знаниями, предлагаю в качестве “Hello world” провести простейший пентест сайта на Wordpress.

Тестовое окружение

Для начала необходимо поднять тестовое окружение. Для этого я буду пользоваться связкой VirtualBox+Vagrant и проектом VCCW, который позволит развернуть готовую виртуалку с Wordpress на борту буквально парой команд в консоли. Подробные инструкции ты сможешь найти на сайте проекта, здесь я покажу основные шаги.

Добавляем базовый образ:

vagrant box add miya0001/vccw

Затем скачаем с сайта проекта архив с Vagrantfile, кукбуками Chef и прочим, распаковываем, переходим в папку где лежит Vagrantfile, и выполним команду:

vagrant up

После этого у тебя должна подняться машина с развернутым Wordpress, доступная по адресу 192.168.33.10. Стоит отметить, что это уже готовый сетап, где настроена база и заведена админская учетка. Логин и пароль от неё указаны на сайте, но мы их узнаем другим путем. :)

Пентест

Откроем консоль Metasploit.

msfconsole

Запустим поиск по слову Wordpress, чтобы найти необходимый модуль.

search wordpress

Среди появившегося многообразия нас интересует модуль auxiliary/scanner/http/wordpress_login_enum который отвечает за брутфорс аутентификации Wordpress.

Результаты поиска модулей по запросу "wordpress"

Выберем его для работы:

use auxiliary/scanner/http/wordpress_login_enum

Чтобы понять как его использовать можно ввести команду info, она выведет краткое описание модуля и список используемых параметров.

Прежде всего, укажем адрес хоста на котором расположен сайт.

set RHOSTS 192.168.33.10

Для брутфорса будет использоваться перебор по словарю. В данном случае известно, что пароль несложный, поэтому подойдет практически любой список ненадежных паролей, которых достаточно в сети. Укажем путь к нему.

set PASS_FILE /root/10k-common-passwords.txt

По умолчанию модуль продолжит перебирать пароли, даже встретив нужный. Это полезно, когда на сайте больше одной учетной записи. В нашем случае, нужно просто остановиться, когда пароль будет найден. Для этого тоже имеется соотвествующая опция.

set STOP_ON_SUCCESS true

Также можно запретить вывод в консоль всех малозначимых сообщений, вроде неудачных попыток авторизации.

set VERBOSE false

Теперь, когда подготовительные действия совершены, осталось ввести последнюю короткую команду и ждать результата:

run

Процесс перебора пароля по словарю в Metasploit

После окончания процесса мы увидим в выводе командной строки, что на сайте был найден пользователь с именем admin и пароль, который к нему подошел был тоже admin.

Результат работы модуля

Итог

Хотя мы и не рассмотрели сотой доли возможностей Metasploit, сегодняшний материал должен стать хорошей отправной точкой в освоении этого инструмента. В конце хотелось бы традиционно напомнить, о том, что любой инструмент можно использовать, как во благо, так и во вред. В неумелых руках использование отдельных компонентов этого фреймворка может нанести серьезный ущерб. Поэтому во-первых используй его только имея соотвествующее разрешение на исследование безопасности от владельца системы. В противном случае ты рискуешь поиметь серьезные проблемы с законом. Во-вторых, даже имея соотвествующее разрешение, не применяй его на продакшн-системах и в сети заказчика, а создай виртуальное, локальное окружение с необходимым софтом (подобно тому, как я показал в статье). Помимо безопасности такого подхода, в качестве бонуса ты получаешь возможность легко откатиться, версионировать, клонировать и совершать другие полезные действия которые помогут упростить исследование.

Ссылки

Homebrew

macOS Homebrew Менеджер пакетов

Homebrew — менеджер пакетов для Mac OS X, который упрощает установку открытого программного обеспечения. Этот проект имеет открытый исходный код, написан на языке Ruby, а его автором является Max Howell.

Зачем нужны менджеры пакетов?

Чтобы понять преимущества использования менеджеров пакетов, рассмотрим типичный процесс сборки из исходников и установки программы в unix-мире на примере Wget.

Сначала потребуется скачать исходный код Wget и распаковать архив. Так как программы пишутся под разные платформы, то перед компиляцией необходимо собрать информацию об используемой операционной системе и подготовить исходники к сборке на ней. Делается это при помощи скрипта конфигурации командой ./configure. Точка и слэш ставятся для того, чтобы указать, что скрипт находится в текущей папке. По умолчанию unix-системы не ищут исполняемые файлы в текущей директории (в целях безопасности).

Компиляция программы осуществляется командой make. Установка, которая заключается (по умолчанию) в перемещении скомпилированного бинарного файла в директорию /usr/local/bin, производится командой make install. После этого можно набрать в консоли wget и увидеть, как запустилась программа.

Нельзя не отметить, что это довольно рутинный процесс, особенно если устанавливать более сложное ПО с большим количеством зависимостей. Чтобы упростить процедуру установки были созданы менеджеры пакетов, которые сводят инсталляцию необходимого ПО к одной команде в консоли. Практически каждый современный дистрибутив Linux поставляется с такой утилитой.

В мире Mac такая практика не столь распространена, так как большинство приложений распространяется через AppStore, либо устанавливается простым «перетягиванием» app-файла в папку Applications. Тем не менее полезно иметь под рукой такой инструмент, особенно если вы перешли на OS X из мира Linux и ощущаете себя некомфортно без привычных утилит вроде mc, wget и т. д.

Обычно в пакетах содержатся уже скомпилированные версии программ. В Homebrew так же некоторые приложения распространяются в собранном виде, но все же стоит отметить, что большинство программ собирается из исходных кодов. Сценарий сборки и установки определяется так называемыми формулами, которые могут быть отредактированы в соответствии с личными потребностями, что обеспечивает высокую гибкость.

Как установить Homebrew?

Для установки Homebrew нужно лишь выполнить в терминале следующую команду:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Homebrew использует версию Ruby, которая идёт в поставке с OS X, поэтому не потребуется устанавливать дополнительных компонентов для запуска скрипта.

Сначала скрипт спрашивает разрешение на продолжение установки, нужно нажать Enter чтобы согласиться. Далее, необходимо будет ввести пароль суперпользователя, для того чтобы разрешить модификацию системных файлов. Затем установщик проверит наличие утилит командной строки разработчика (xcode-select, необходимы для компиляции) и при их отсутствии попытается установить. Последним этапом будет непосредственная установка исполняемых файлов Homebrew.

Процесс установки Homebrew

Проверить, что программа установилась корректно, можно при помощи команды для диагностики brew doctor.

Использование

Обновить Homebrew: brew update.

Показать список установленных приложений: brew list.

Поиск приложений осуществляется командой search.

brew search mc

Установка приложения выполняется командой install.

brew install mc

Удаление приложения - remove.

brew remove mc

Сайт проекта
Репозиторий на GitHub

Альтернативы Homebrew

  • MacPorts — развитие проекта DarwinPorts, инициативы по портированию unix-приложений на платформу Darwin, которая является основой Mac OS X. Используется для сборки и установки приложений с открытым исходным кодом;
  • Fink - ещё один проект по портированию открытых unix-программ на OS X. Использует dpkg и APT.

Основы автоматизации сборки при помощи Rake

Ruby Rake .NET DevOps Журнал Хакер

Эта статья была впервые опубликована в журнале “Хакер”, здесь публикуется исходная версия, до отправки в редакцию.

С Rake знакомы многие кто писал веб-приложения на Ruby on Rails. Но этот инструмент для автоматизации сборки может оказаться весьма полезен и вне контекста популярного веб-фреймворка. Предлагаю разобраться подробнее с его базовыми принципами и подумать где еще он может пригодиться.

Введение

Разработка любого проекта постоянно связана с автоматизацией сопутствующих рутинных задач. Сначала хватает средств IDE + пары ручных операций. Затем количество телодвижений начинает расти: требуется выполнять несколько наборов тестов, подкладывать какие-нибудь сертификаты, прогонять скрипты на базе данных, генерировать документацию к коду и т.д. Также нужно выполнять эти и другие операции на Continuous Integration сервере, а возможно и осуществлять деплой приложения на продакшн-сервера (если говорить о каком-либо клиент-серверном решении). Иногда это автоматизируют при помощи набора самописных batch- или shell-скриптов, но чаще всего в командах разработчиков приходят к какому-то консолидированному решению.

Для каждой платформы существует уже устоявшийся набор инструментов автоматизации, они довольно разнообразны и каждый использует свой синтаксис и философию. Тем не менее в том или ином виде они используют некие конфигурационные файлы, в котором описаны задания, зависимости между ними и порядок выполнения. В зависимости от используемого языка описания такие инструменты можно условно разделить на декларативные, где, как правило на XML, описываются необходимые действия и императивные где задания реализуются в виде кода, который пишется с учетом некоторых соглашений.

На первый взгляд, декларативный подход выглядит более выгодным, так как позволяет добиться желаемых результатов описав задания в сравнительно несложном XML или ином синтаксисе. С другой стороны, рано или поздно упираешься в ограничения реализации самого инструмента (например, скопировать/удалить файлы по какой-нибудь сложной маске), плюс когда требуется реализовать сложный воркфлоу (к примеру, в зависимости от версии приложения и платформы под которую оно собирается подкладывать нужные конфиги и скрипты), приходится писать собственные экстеншены, которые в свою очередь приходится тоже мантейнить, тестировать и т.д. А раз написание кода все равно неизбежно, то почему бы не реализовать необходимые действия сразу в коде, причем в удобном формате?

Именно об одном из таких инструментов сегодня пойдет речь. Rake широко используется в известном веб-фреймворке Ruby on Rails и других Ruby-проектах, но у меня вполне удачно получалось его сочитать с другими технологиями, в частности с .NET, что мы рассмотрим сегодня в качестве примера.

Rake - это инструмент автоматизации сборки программного кода, написанный на Ruby. Это проект с открытым исходным кодом, автором которого являлся ныне покойный Джим Вайрих. Своей целью он ставил создание инструмента подобного распространенным Make, Ant и MSBuild, сделав его более простым и гибким. Сам автор выделяет следующие особенности Rake:

  • Простой DSL на основе Ruby позволяет использовать всю мощь языка и не требует составления сложных XML и других конфигурационных файлов;
  • Параллельное выполнение нескольких заданий;
  • Шаблоны правил для синтеза неявных заданий;
  • Библиотека готовых заданий, для выполнения типичных задач;
  • Возможность указывать начальные условия для заданий.

Установка

Rake распространяется в виде библиотеки для Ruby. Версии языка, начиная от 1.9 и выше, уже включают его в себя, не требуя дополнительной установки. Если используется Ruby версии 1.8, или есть необходимость установить более свежую версию Rake, чем идет в комплекте с языком, то можно воспользоваться системой управления пакетами RubyGems, выполнив команду:

gem install rake

Задания

Конфигурационный файл в контексте Rake называется Rakefile. Его основными “строительными блоками” являются задания (tasks). Задание обладает именем, набором начальных условий и списоком действий, которые должны быть выполнены.

task name: [:prereq1, :prereq2]

Действия передаются в конструкции, которая в Ruby называется блок (block).

task name: [:prereq1, :prereq2] do |t|
  # actions
end

Условно задания в Rake можно разделить на два типа: обычные и файловые. Обычное задание - это просто набор действий, который нужно выполнить. Такое задание объявляется методом task.

Назначением файлового задания является генерация файла (как правило на основе одного или более уже существующих). Если файл уже существует, то такое задание не выполняется (пропускается). Файловое задание объявляется методом file.

Имя задания, которое нужно выполнить передается в качестве параметра утилите rake.

rake task_name

Если запустить rake без параметров, то он будет пытаться найти в Rakefile задание с именем “default”. Если задание с таким именем не будет найдено, то rake выдаст соотвествующую ошибку.

>rake
rake aborted!
Don't know how to build task 'default'

Комментарии

Хотя в Rake разрешаются ruby-комментарии при помощи символа “#”, хорошим тоном считается писать комментарии к заданиям при помощи ключевого слова desc.

В этом случае, запустив команду rake -T мы получим список заданий с описаниями. Таким образом, хорошо составленные описания избавляют от необходимости дополнительно документировать rake-скрипты.

Пример вывода команды 'rake -T'

Пространства имен

В Rake есть концепция пространств имен (namespaces) для объединения заданий в группы. К примеру, любой, кто писал на Ruby on Rails, использовал команду rake db:migrate, в данном случае db - это пространство имен, а migrate задание в которое в него входит. Пространство имен объявляется ключевым словом namespace.

namespace :namespace_name do
     # tasks
end

Организация Rake-файлов

Утилита Rake ищет задания в файле с названием Rakefile. Очень быстро этот файл разрастается и возникает необходимость его разбить на несколько файлов по функциональному назначению. Для этого нужно воспользоваться следующим соглашением: создаем папку с названием rakelib, а в ней файлы с расширением *.rake. На все задания и пространства имен объявленные в *.rake-файлах можно ссылаться из основного Rakefile.

Сборка .NET проекта при помощи Rake

Ожидаемо, что чаще всего использование Rake встречается в Ruby/Rails проектах. Тем не менее никто не запрещает нам применить его в других языках. В качестве примера рассмотрим сборку простого “Hello world” на C#. Использование Rake в .NET-проектах может быть вполне оправдано, когда требуется реализовать сложную логику для сборки/тестирования/развертывания приложения, что может оказаться весьма нетривиально реализовать в XML-декларациях привычных NAnt или MSBuild.

Исходник будет представлять собой файл с простейшим кодом и файл с проектом для того чтобы воспользоваться MSBuild. Здесь он избыточно простой, но подход будет тот же, что и при билде больших солюшенов.

using System;

public class HelloWorld
{
    static void Main()
    {
        Console.WriteLine("Hello world!");
        Console.ReadLine();
    }
}

Файл проекта в этом случае будет выглядеть таким образом:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
        <Compile Include="hello.cs" />
    </ItemGroup>
    <Target Name="Build">
        <Csc Sources="@(Compile)"/>
    </Target>
</Project>

Так как Rake-код получается достаточно простой, я приведу его полностью, а затем поясню.

require "fileutils"

task :default => [:clean, :build, :pkg]

msbuild = "#{ENV['WINDIR']}\\Microsoft.NET\\Framework\\v3.5\\msbuild.exe"
proj_root = File.dirname(__FILE__)
out_dir = "#{proj_root}/out"

desc "Clean the artefacts from previous build"
task :clean do
    rm Dir.glob('*.exe')
    rm_rf(out_dir) if Dir.exists?(out_dir)
end

desc "Compile project with MSBuild"
task :build do
    mkdir_p(out_dir) if !Dir.exists?(out_dir)
    project = "#{proj_root}/hello.proj"
    cmd = "\"#{msbuild}\" #{project}"

    sh cmd do |ok, res|
        raise "*** BUILD FAILED! ***" if !ok
    end
end

desc "Prepare deploy package"
task :pkg do
    artefacts = ["#{proj_root}/hello.exe",
                "#{proj_root}/readme.txt"]
    cp_r(artefacts, out_dir)
end

У нашего проекта определены следующие стадии сборки:

  • Очистка (Clean) - на этой стадии будут чиститься артефакты от предыдущего билда. В данном случае удаляются все *.exe файлы и папка out;
  • Сборка (Build) - все что касается компиляции приложения. В данном случае мы передаем MSBuild в качестве параметра путь к proj-файлу и выполняем эту команду;
  • Подготовка к поставке (Package) - здесь собранный exe-файл перемещается в папку “out”, а также подкладываться файл с ReadMe.

Задание default не выполняет никаких действий, но зависит от остальных объявленных заданий, таким образом, выполнив команду rake без параметров мы запустим друг за другом задания clean, build и package. Также хочу отметить, что в Rakefile, как и в обычных Ruby-скриптах можно пользоваться оператором require для того чтобы загружать и использовать любые библиотеки языка.

Результат выполнения Rake-скрипта из примера

Albacore

Я не единственный, кто захотел использовать Rake для сборки .NET-проектов. Для этого существует довольно популярный проект под названием Albacore, который расширяет DSL Rake, специальными ключевыми словами для автоматизации типичных задач с которыми сталкиваются разработчики для платформы от Microsoft.

Установка осуществляется командой:

gem install albacore

Давайте рассмотрим, как будет выглядеть задание сборки с использованием Albacore:

require "albacore"

desc "Compile project with MSBuild using Albacore"
build :alba_build do |b|
  b.file = "#{proj_root}/hello.proj"
end

Согласитесь, код стал выглядеть гораздо компактнее. Полную информацию по синтаксису Albacore можно найти в wiki проекта на Github.

Заключение

Rake - это отличный, гибкий инструмент для создания различных скриптов для сборки и обслуживания ваших проектов. Его использование совершенно не ограничивается Ruby-экосистемой, мы смогли убедиться, что ему найдется место даже в .NET-инфраструре.

Конечно не стоит вносить лишнюю зависимость на Ruby в небольшие проекты, где легко можно обойтись средствами, которые предоставляет платформа. В сложных же проектах, особенно при поддержке legacy-систем, где требуется при сборке разрешать сложные зависимости, подготавливать окружение для тестов (к примеру регистрировать COM-объекты в системе по набору определенных условий) и многое другое, Rake поможет сэкономить большое количество времени при минимальном количестве кода.

Альтернативы Rake:

Thor

Thor за авторством Yehuda Katz - это тулкит для создания консольных приложений на Ruby. В последнее время он также становится все популярнее в Ruby-сообществе в качестве замены Rake, так как имея схожую философию позволяет писать код на чистом Ruby, не требуя освоения специфичного Rake DSL и следования его соглашениям. Часто это позволяет облегчить внедрение инструмента в существующую инфраструктуру, покрыть скрипты автоматизации тестами и т.д.

Grunt

Grunt широко используется в мире фронтенд веб-разработки и позволяет реализовать задания на Javascript, a также обладает большим количеством плагинов. Мне также встречалось его использование вне контекста фронтенд-разработки.

Paver

Если для автоматизации рутинных задач ты предпочитаешь использовать Python вместо Ruby, то всю мощь и простоту Rake тебе сможет принести Paver. Используя схожий с Rake подход и философию, он позволяет также решать специфичные для Python задачи вроде разворачивания виртуальных окружений, содержит врапперы для генераторов документации и многое другое.

Gradle

В мире Java даже относительно простые проекты редко обходятся без использования инструментов сборки, обычно это Ant или Maven использующие конфиги в виде *.xml-файлов. Gradle позволяет отойти от декларативного подхода и реализовать задания в виде кода на Groovy DSL.

Ссылки

Примеры кода из статьи

Vagrant: наполнение виртуальной машины при помощи shell-скрипта

Vagrant VirtualBox DevOps Ruby

Создавать виртуалку при помощи Vagrant легко и весело, но пустая виртуалка врядли будет кому-то полезна и интересна. Раз уж мы автоматизировали создание виртуальной машины, то почему бы не автоматизировать установку необходимого программного обеспечения? В терминологии Vagrant такой процесс называется наполнением (provisioning).

В следующих статьях мы поговорим, как это делается при помощи популярного средства управления конфигурацией Chef, а сегодня я рассмотрю самый простой способ: использование shell-скрипта. Часто этот способ игнорируется, хотя для простых решений написать скрипт на 10 строчек может оказаться гораздо быстрее, чем разбираться с cookbook’ами Chef и их зависимостями.

Eсли вы читали мою первую заметку, то у вас уже должен быть минимальный Vagrantfile вида:

# -*- mode: ruby -*-
 
VAGRANTFILE_API_VERSION = "2"
 
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "precise32"
  config.vm.box_url = "http://files.vagrantup.com/precise32.box"
end

Допустим вам необходимо установить mysql. Для этого после конфигурации машины нужно написать:

config.vm.provision :shell, :inline => “sudo apt-get -q -y install mysql-server”

Здесь я указал, что в качестве «наполнителя» хочу использовать командную строку, а затем передаю команду. Это очень удобно когда вам нужно выполнить 1-2 команды, но скорее всего у вас будет более длинная последовательность, которую вы захотите вынести в отдельный файл. В этом случае команда будет выглядеть следующим образом:

config.vm.provision :shell, :path => “my_awesome_script.sh”

Если вы еще не создавали виртуалку, то достаточно запустить vagrant up, и после создания виртуалки автоматически накатится ваш скрипт. Если же виртуалка уже создана и работает, то достаточно запустить vagrant provision чтобы накатить скрипт с конфигурацией.

Vagrant: работа с несколькими машинами

Vagrant VirtualBox DevOps Ruby

Описание конфигурации в Vagrantfile не ограничивается только одной машиной. Если для вашего окружения нужно поднять несколько машин (эмуляция распределенной работы, к примеру), их конфигурации можно описать в едином файле, выделив для каждой из машин отдельный блок. Вот хороший  пример из документации:

Vagrant.configure("2") do |config|
  config.vm.provision "shell", inline: "echo Hello"

  config.vm.define "web" do |web|
    web.vm.box = "apache"
  end

  config.vm.define "db" do |db|
    db.vm.box = "mysql"
  end
end

Таким образом можно задать любое необходимое количество машин. Стоит отметить, что если продолжить задавать свойства через переменную config, они будут применены ко всем машинам. Индивидуальные же свойства следует указывать в блоке с config.vm.define. Запускать машины можно будет и по-отдельности, например: vagrant up web.

Аналогично можно поступать, если у вас несколько проектов и для каждого свой Vagrantfile. Лично мне удобно держать именно отдельный отдельный файл в папке для каждого проекта, чтобы у каждого была своя независимая конфигурация, плюс можно легко поделиться им с
человеком, который захочет со мной совместно поработать.

В любом случае, перед тем как писать конфиг машины, добавляю блок с define с названием проекта, что позволяет мне не задумываясь запускать машины. Это делать вовсе не обязательно, но получается удобно, когда ты видишь, что имя машины не «default», а соответствует названию проекта. Если вдруг у двух проектов стали просматриваться точки интеграции, то для proof-of-concept могу запросто их объединить в один простым copy-paste (речь только о Vagrantfile конечно же :) ).

Кстати, насчет имени машины. Vagrant дает им совершенно сумасшедшие имена.

Чтобы дать нормальное имя, нужно в блоке vm.provider задать параметр name равным желаемому имени.

Пример:

zc.vm.provider "virtualbox" do |vb|
  vb.name = "zencity"
end

Даст соответствующий результат.

Vagrant: автоматизация создания виртуальных машин

Vagrant VirtualBox DevOps Ruby

Vagrant  — это набор скриптов на Ruby, который предназначен для того, чтобы автоматизировать работу с виртуальными машинами на вашем компьютере. Чаще всего он используется для быстрого развертывания окружения для разработки ПО.

Зачем может понадобиться использовать виртуальную машину для разработки? Причин тому может быть много. Прежде всего, это необходимость использования разных версий библиотек и компонентов в разных проектах, а также разработка приложений под конкретную среду.

Кажется, что это не так уж и важно, но на самом деле, гораздо удобнее развернуть виртуалку с нужными вещами, чем засорять систему и ломать голову, как разрулить какие-нибудь конфликты. Думаю каждый, кто работал с крупными проектами, сталкивался с подобным вещами. Обычно развернуть и настроить среду в виртуальной машине не очень сложно, но, как правило, занимает довольно много времени. Vagrant позволяет избавиться от всей этой рутины.

Установка

Автор постарался и сделал нормальные установщики под все операционные системы [1]. На протяжении всего повествования мы будем пользоваться средством виртуализации Virtual Box [2], так как Vagrant создавался в первую очередь для него. Предпочитающие VMware, тоже могут воспользоваться Vagrant, подробности есть у них на сайте [3].

Настройка

После того, как вы установили Vagrant, потребуется создать файл файл с настройками машины, который называется Vagrantfile. Нет нужды создавать его самостоятельно, для этого есть соотвествующая команда vagrant init.

Для себя выработал такую практику: в папке каждого проекта есть папка /env, в которой лежат все файлы нужные для того, чтобы с нуля развернуть девелоперское окружение. Там создаю Vagrantfile, кладу необходимые кукбуки для Chef и т.д.

Важный момент, который нужно учитывать при работе с Vagrantfile: Vagrant использует не только тот файл, который лежит непосредственно в папке вашего проекта, но и тот, который поставляется с базовым образом машины, тот что лежит в папке с настройками (~/.vagrant.d) и т.д. Полный перечень и принцип работы подробнее можно посмотреть в документации [4].

Теперь откроем получившийся Vagrant-файл. В нем вы увидите код на Ruby и множество закомментированных строчек. Уверен, что большинству для базовой настройки будет достаточно раскомментировать нужные строчки и вписать в них необходимые значения. Далее я просто рассмотрю самые важные для нас понятия.

Если удалить все комментарии, то минимальная конфигурация, которая должна содержаться в Vagrantfile будет выглядеть следующим образом:

# -*- mode: ruby -*-
 
VAGRANTFILE_API_VERSION = "2"
 
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "precise32"
  config.vm.box_url = "http://files.vagrantup.com/precise32.box"
end

Здесь я написал, что хочу использовать 32-битную Ubuntu 12.04, и указал URL по которому её можно скачать. Этого же результата можно было добиться просто запустив команду init с соотвествующими параметрами.

vagrant init precise32 http://files.vagrantup.com/precise32.box

Уверен, вызывает вопрос расширение *.box. Никакой особенной магии тут нет: это обычный zip-архив в котором лежит vmdk-образ виртуальной машины и Vagrantfile с дефолтными настройками. У Vagrant довольно большое сообщество, и базовую сборку на любой вкус можно найти на сайте vagrantbox.es.

Скорее всего, просто с дефолтными параметрами запускать машину никому не захочется. Все что я напишу далее, можно найти и в комментариях сгенерированного вами Vagrantfile, я же просто заострю внимание на самых значимых вещах. Девелоперское окружение подразумевает хотя бы наличие расшареных папок и портов (чтобы вы работали в своем привычном окружении, а ваш софт — в своем).

config.vm.network "forwarded_port", guest: 3000, host: 3333
config.vm.synced_folder "../project_folder_host", “/project_folder_guest”

Думаю из примера очевидно: первая строчка отвечает за форвардинг портов (как можно догадаться, это порт по-умолчанию сервера в Rails) c гостевой машины на хост. Вторая строчка отвечает за создание «прозрачной» папки на гостевой машине.

Естественно, можно сконфигурировать и параметры самой виртуальной машины, например увеличим оперативную память:

config.vm.provider "virtualbox" do |vb|
  vb.customize ["modifyvm", :id, "--memory", "1024"]
end

Важный момент: по-умолчанию в Vagrant машина запускается в headless-режиме, т.е. вы не увидите окно Virtual Box с ОС внутри. Предполагается, что общение с виртуалкой будет происходить по SSH. Если по каким-либо причинам вас это не устраивает, то в этот же блок нужно добавить:

vb.gui = true

На всякий случай, приведу полный пример конфига.

# -*- mode: ruby -*-
 
VAGRANTFILE_API_VERSION = "2"
 
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "precise32"
  config.vm.box_url = "http://files.vagrantup.com/precise32.box"
  config.vm.network "forwarded_port", guest: 3000, host: 3333
  config.vm.synced_folder "../project_folder_host", “/project_folder_guest”
 
  config.vm.provider "virtualbox" do |vb|
    vb.customize ["modifyvm", :id, "--memory", "1024"]
  end
 
end

Я написал много букв, но как видите, настройка сводится к указанию небольшого количества параметров и совершенно не требует знания Ruby.

Запуск, остановка и удаление машины

Запуск машины производится командой vagrant up (из той же папки, где лежит Vagrantfile). После этого автоматически скачается базовый образ, указанный в url, создастся и запустится виртуальная машина, к которой можно будет присоединиться по SSH (словом, нужно только дождаться появления сообщения: «Machine booted and ready!»). Далее пишем vagrant ssh, откроется соединение с машиной и можно делать все, что душа пожелает.

Когда наиграетесь, появится закономерное желание выключить машину. Для этого:
vagrant suspend — сохранить состояние машины;
vagrant halt — выключить машину.

Все сломали своими экспериментами и хотите полностью удалить машину?
vagrant destroy — удаляет машину, создать заново с нуля можно будет в любой момент при помощи vagrant up!

[1] Страница загрузок Vagrant
[2] Страница загрузок VirtualBox
[3] Информация об использовании Vagrant с VMware
[4] Документация по Vagrantfile

Радиаторы для Raspberry Pi

Linux Raspberry Pi GnuPlot Python Мои проекты

Решил сделать радиаторы для своего Raspberry Pi. Нагревался процессор, если его хорошенько нагрузить, прилично, да и насмотревшись «ужасных» фотографий, наподобие той что ниже, было решено попробовать хоть немного предохранить чипы от перегрева.

По большому счету даже 60 градусов — вполне нормальная рабочая температура для процессора, но кто знает, что может случиться, если хорошенько нагрузить устройство, да еще и жарким летом? Ничего не произойдет, но отговаривать было бесполезно, поэтому начались поиски донора. Да, можно было купить, что-то более или менее подходящее, но это не спортивно. Долго искать не придется, если знать к кому обратиться, и уже вскоре один мой хороший друг приволок мне вот такой радиатор.

Первым делом, нужно было счистить остатки старого клея. Основную часть, я соскреб металлической линейкой, остальное удалил при помощи ацетона.

Далее замерил размеры чипов, разметил, взял ножовку по металлу и начал пилить. Тут стоит сделать замечание для тех, кто соберется повторять мой подвиг. Учитывайте, далеко не факт, что вам удастся отпилить красиво и ровно, 146% что придется доводить напильником до божеского вида.

Я делал запас 1-2 миллиметра (на глаз) и это как раз было впритык. Далее выравнивание напильником и шкуркой, в результате получилось 3 маленьких радиатора. К идеалам не стремился: более или менее ровно и ладно.

Теперь осталось приклеить. Почитав, что пишут духи в онлайне и ознакомившись с ассортиментом местных магазинов, я понял, что у меня 2 варианта:

  • Термоклей Алсил-5, штука сомнительная, но ничего другого не обнаружилось на прилавках.
  • Намазать чип в середине термопастой, а по краям посадить на маленькие капельки суперклея.

Немного подумав, решил пойти по пути наименьшего сопротивления и взял Алсил-5.

Попытавшись его выдавить, понял о чем писали на форумах: в «носике» шприца клей был намертво засохшим. Расковыряв его зубочисткой, обезжирил поверхности чипов и радиаторов, нанес клей небольшим слоем, приладил чипы и положил сверху толстых, умных книжек (должна же быть от них хоть какая-то польза). Через сутки (раньше не получилось) проверил: все отлично приклеилось.

Эксперименты

Пытливый мозг не дает покоя. Надо попытаться проверить. Градусников, термометров и прочей измерительной аппаратуры не имею. Поэтому за неимением лучшего выдавил из себя немного кода на Python:

#!/usr/bin/python
 
from time import sleep
 
f = open('temp.txt','w')
 
for i in range(12) :
    sleep(600)
    cpuTemp = str(round(int(open('/sys/class/thermal/thermal_zone0/temp').read())/1e3, 1))
    print cpuTemp
    f.write(cpuTemp + 'n')
 
f.close

Это дало мне несколько значений температуры процессора, в попытке визуализировать полученную информацию, набросал следующий код на GnuPlot:

#! /usr/bin/gnuplot -persist
 
set terminal png size 800, 600
set output "result.png"
set grid xtics ytics
 
set xlabel "Time, minutes"
set ylabel "Temperature, 260C" rotate by 90
 
set style line 1 lw 3 linecolor rgb "#FF0066"
 
plot "~/temp.txt" using (column(0)*10):1 w l ls 1 notitle smooth csplines

Далее аналогичным способом был произведен замер результатов с радиаторами. Получился такой результат:

Если кому интересно, то код для GnuPlot в этом случае такой:

#! /usr/bin/gnuplot -persist
 
set terminal png size 800, 600
set output "result.png"
set key spacing 1.30
set grid xtics ytics
 
set xlabel "Time, minutes"
set ylabel "Temperature, 260C" rotate by 90
 
set yrange [44:48]
set xrange [0:100]
 
set style line 1 lw 3 linecolor rgb "#FF0066"
set style line 2 lw 3 linecolor rgb "#3366FF"
 
set multiplot
 
plot "~/temp.txt" using (column(0)*10):1 w l ls 1 title "without heat sink"smooth csplines, /
     "~/temp_n.txt" using (column(0)*10):1 w l ls 2 title "with heat sink" smooth csplines
 
unset multiplot

Applescript: язык автоматизации для macOS

macOS Applescript

AppleScript — скриптовый язык, который используется для управления системой, приложениями и файлами в Mac OS X. Наиболее общий принцип применения следующий: открыть приложение и передать ему набор инструкций для выполнения. Причем это не обязательно приложения из стандартного комплекта поставки операционки, многие сторонние приложения также предоставляют API для обращения к ним через AppleScript.

Для редактирования и запуска скриптов есть небольшой редактор, который находится в Application > Utilites > AppleScript Edtior. Редактор довольно минималистичный и не имеет богатых возможностей, но для написания небольших скриптов его обычно оказывается вполне достаточно. Условно его можно разделить на две части: в первой пишется непосредственно сам код, а в нижней части, показывается результат выполнения твоих трудов. Если вдруг возникнет необходимость сделать более или менее серьезный проект, то удобнее будет воспользоваться какой-нибудь сторонней разработкой, например Script Debugger.

Азы

Applescript имеет очень простой синтаксис, который был максимально приближен к обычному английскому языку, давай быстро пробежимся по основным операторам, чтобы понимать, как нам выполнять самые базовые вещи.

Чтобы задать переменную нужно воспользоваться оператором set. Делается это так:

set <имя переменной> to <значение>

Имя переменной не должно совпадать с зарезервированными словами (beep, say и т.д.), а также нельзя начинать имя переменной с цифры.

Условия задаются при помощи оператора if, как и в других языках:

set a to true
if a is true then
     say "That's true"
else
     say "That's false"
end if

Оператор say произносит переданный ему текст. Вместо «is» можно писать привычный знак равенства.

Задать цикл можно оператором repeat. В самом простом случае достаточно написать:

repeat 2 times
     beep
end repeat

Этот цикл 2 раза воспроизведет стандартный системный звук. Если нужны итерационные циклы, то их можно задать используя until или while, например:

set i to 1
repeat until i is 10
     beep
     set i to i + 1
end repeat

Арифметический цикл можно задать при помощи with таким образом:

repeat with i from 1 to 20 by 2
     say i
end repeat

Я думаю, понятно, что этот код будет произносить числа от 1 до 20 с шагом 2. Сейчас я быстро прошелся по основным «школьным» азам, чтобы было понятно что это за язык и с чем его едят. Как видишь, разработчики старались делать его таким, чтобы пользователи с разным уровнем подготовки могли «говорить» с компьютером практически человеческим языком. Я не буду подробно останавливаться на всех особенностях синтаксиса, если возникнут вопросы, ты всегда сможешь найти ответы в документации на сайте Apple.

Диалоги с пользователем

AppleScript не был бы так интересен, если бы не возможность легко создавать различные диалоговые окна, что дает нам возможность сделать наши скрипты более user-friendly.

Давай начнем с вызова стандартного системного диалога выбора файла. Делается это при помощи команды choose file.

set filePath to choose file of type {"PDF", "MOBI"} with multiple selections allowed

В данном примере, будет вызван диалог выбора файла в котором включена фильтрация по типу (pdf или mobi) и разрешен выбор нескольких файлов. Если ты выполнишь этот код, то заметишь, что путь к файлу запишется, как alias:

System:Users:UserName:file.pdf   

Такой формат понимают стандартные приложения в Mac OS, но часто требуется использовать привычный нам POSIX-вид, делается это легко:

set posixFilePath to POSIX path of filePath

В переменную posixFilePath путь запишется в виде: /Users/UserName/file.pdf.

Аналогичным способом выбирается папка при помощи choose folder. Чтобы показать свое, кастомное сообщение пользователю, нужно воспользоваться командой:

display dialog "Твое сообщение" with title "Заголовок"

Если не было передано никаких параметров, то будет выведен стандартный диалог с кнопками «ОК» и «Cancel». Тут стоит отметить, что после вывода диалога скрипт приостановит выполнение, и продолжит выполняться после нажатия «ОК», а вот после «Cancel» выполнение скрипта будет прервано с соответствующей ошибкой «User canceled.». Если такое поведение в твои планы не входит, то самое простое, — воспользоваться обработчиком ошибок:

try
     display dialog "Нажми Cancel"
on error
     display dialog "Ты нажал Cancel :)"
end try

Естественно, может такое случиться, что потребуются другие кнопки, кроме «Cancel» и «OK», и ты конечно же волен добавить любые, которые захочешь (но не больше трех). Делается это следующим образом:

display dialog "Are you sure?" buttons {"Don't know", "Not sure", "Maybe"}

А как быть, если требуется дать пользователю выбрать что-нибудь из списка? Легко:

choose from list {"1", "2", "3"} with title "Choose it!" with prompt "Choose somethng:"

В случае если нужно будет просто ввести какие-либо данные воспользуйся такой строчкой:

display dialog "What is your name?" default answer "

Диалоги с софтом

Как я отметил в начале, главным козырем AppleScript является возможность автоматизации действий в различных приложениях, что дает практически безграничные возможности по его применению. Для того чтобы передать команду приложением нужно воспользоваться блоком tell.

tell application "Имя приложения"
     -- Действия
end tell

Например, очистим корзину:

tell application "Finder"
     empty trash
end tell

Чтобы узнать какие действия доступны для того или иного приложения, в AppleScript имеется средство, которое называется Dictionary, оно доступно в меню File > Open dictionary.

Также имеется возможность передачи команд на удаленный компьютер. Для начала, нужно включить опцию Remote Apple Events на машине, где требуется выполнить какие-либо действия в System Preferences > Sharing. Теперь, чтобы выполнить код на другой машине, нужно использовать следующую конструкцию:

tell application "Имя приложения" of machine "epic://ip-адрес"

Будь готов, что для выполнения действия на удаленной машине скрипт запросит логин и пароль, так что если ты потираешь руки, чтобы творить беспредел, придется придумать что-то еще :).

Командная строка

После прочтения предыдущих двух разделов у тебя наверняка должна была зародиться мысль о том, что неплохо было бы соединить удобство AppleScript с мощью shell-скриптов. Первое, что приходит в голову, — воспользоваться знаниями из предыдущего раздела и скормить необходимые команды приложению Terminal.

tell application "Terminal"
     do script "ping -c 1 ya.ru"
end tell

Такой способ имеет право на существование и в отдельных случаях он может быть даже предпочтительнее, но есть другой вариант: воспользоваться командой do shell script, при помощи которой можно также выполнять консольные команды, что гораздо более удобно, так как дает возможность записать результат выполнения команды в переменную и оперировать с ней дальше средствами AppleScript.

← Сюда 2 of 3 Туда →