+1.55
0 читателей, 6 топиков

Как сохранять видео с Youtube, Vimeo, Facebook и прочих видеохостингов.

Во всех современных версиях браузера Internet Explorer есть замечательный инструмент «Средства разработчика», который вызывается по кнопке F12.
Этот инструмент позволяет делать огромное количество интересных вещей. Например, сохранять потоковое видео с видеохостингов Youtube, Vimeo, Facebook и прочих.

Перед сохранением рекомендую закрыть все остальные вкладки браузера, что бы лишние сайты не мешали анализу.
Вызываем окно средств разработчика, переходим в закладку «Сеть» и в зависимости от версии браузера нажимаем «начать сбор» или на кнопку в виде зеленого треугольника.
Заходим на нужную страницу видеохостинга и начинаем просмотр. Обычно даже нет необходимости дожидаться конца загрузки видео.
Останавливаем сбор траффика в средствах разработчика, и выбираем большой по размеру объект в несколько килобайт или мегабайт. Нажимаем на нём правой кнопкой и выбираем «скопировать URL-адрес».
Для Vimeo у меня получился вот такой адрес — http://pdl.vimeocdn.com/46595/158/20435435353473.mp4?token2=49773535445523434467843&aksessionid=e99af67537925, это адрес видео.
C Youtube немного сложнее. Плеер скачивает по кускам видео и звук отдельно, но это не проблема.
В логах будет несколько объектов размером по полтора мегабайта и около 200 кмлобайт. Первое — видео, второое — аудио.
Берем любой адрес видео, копируем в блокнот и ищем в середине хитрый параметр
...&mt=1404904408&mv=m&mws=yes&range=6266880-8355839&ratebypass=yes&signature=4432BD630E39…
Это временной интервал, меняем его на «range=0-999999999999» и получаем адрес видео.
С аудио тоже самое. С помощью VLC можно просмотреть видео с аудиодорожкой.

Если просто ввести адрес в строке браузера, он его может не сохранить, а начать проигрывать. Поэтому я применяю для сохранения следующий трюк — открываю MS Word, копирую в пустой документ этот адрес, нажимаю после ссылки пробел или ентер, что бы это превратилось в ссылку и сохраняю полученный документ как веб-страницу. Открыв полученную страницу в браузере теперь можно будет нажать на ссылке правой кнопкой и сохранить объект. При необходимости переименуйте файл, установив расширение mp4 или иное расширение видео-файлов.

NopCommerce: Подстановка города.

В недавнем посте я приводил пример импорта областей России в CMS NopCommerce.
Так же, как и в Википедии, у меня в списке областей присутствуют города Москва, Санкт-Петербург и Севастополь.
Это выглядит логичным, но порождает небольшую проблему интерфейса: при выборе города Москва поле «город» остается пустым и требуется доввести туда город.
Исправить эту мелкую ошибку достаточно просто небольшим дописыванием на JavaScript. В файлы _CreateOrUpdateAddress.cshtml и _CreateOrUpdateAddress.Mobile.cshtml надо внести следующее изменение:

<script type="text/javascript">
$(function () {

	$("#@Html.FieldIdFor(model => model.CountryId)").change(function () {
		var selectedItem = $(this).val();
		var ddlStates = $("#@Html.FieldIdFor(model => model.StateProvinceId)");
		var statesProgress = $("#states-loading-progress");
		statesProgress.show();
		$.ajax({
			cache: false,
			type: "GET",
			url: "@(Url.RouteUrl("GetStatesByCountryId"))",
			data: { "countryId": selectedItem, "addEmptyStateIfRequired": "true" },
			success: function (data) {
				ddlStates.html('');
				$.each(data, function (id, option) {
					ddlStates.append($('<option></option>').val(option.id).html(option.name));
				});
				statesProgress.hide();
			},
			error: function (xhr, ajaxOptions, thrownError) {
				alert('Failed to retrieve states.');
				statesProgress.hide();
			}
		});
// Начало добавления
		
		var StateProvinceText = $("#Address_CountryId option:selected").text();
		if(!StateProvinceText)  {
			var StateProvinceText = $("#NewAddress_CountryId option:selected").text();
		}
		
		if (StateProvinceText == 'Россия' ) {
			$('#Address_City').attr('value', 'Москва');
			$('#NewAddress_City').attr('value', 'Москва');
		}
		if (StateProvinceText == 'Russia' ) {
			$('#Address_City').attr('value', 'Moscow');
			$('#NewAddress_City').attr('value', 'Moscow');
		}
	});

	$("#@Html.FieldIdFor(model => model.StateProvinceId)").change(function () {
		var StateProvinceText = $("#Address_StateProvinceId option:selected").text().replace("г. ", "");
		if(!StateProvinceText)  {
			var StateProvinceText = $("#NewAddress_StateProvinceId option:selected").text().replace("г. ", "");
		}

		if (StateProvinceText == 'Москва' || 
			StateProvinceText == 'Санкт-Петербург' ||
			StateProvinceText == 'Севастополь' || 
			StateProvinceText == 'Moscow' || 
			StateProvinceText == 'Saint Petersburg' || 
			StateProvinceText == 'Sevastopol') {
				$('#Address_City').attr('value', StateProvinceText);
				$('#NewAddress_City').attr('value', StateProvinceText);
		}
// Конец добавления 
	});
});
</script>

В первой половине добавленного кода производится установка города по умолчанию (Москва)

NopCommerce и почта России. Часть 2. Прописываем тарифы.

Часть 2. Прописываем тарифы.
Это — вторая часть серии постов, посвященная настройке CMS на основе NopCommerce для работы с почтой России.

Что бы внести тарифы на доставку с помощью Почты России, достаточно воспользоваться стандартным модулем расчета «Shipping by weight» и небольшим SQL скриптом.

Тарифы Почты России
Само описание тарифов можно посмотреть на сайте Почты России по адресу www.russianpost.ru/rp/servise/ru/home/postuslug/bookpostandparcel/local
Для Москвы тарифы следующие: Россия раздяется на 5 магистральных поясов и доставка до каждого пояса стоит фиксированную сумму за посылку весом до 500 гр. За каждые следующие 500 гр взимается фиксированная доплата.

Стоимости доставки по 1-му магистральному поясу: 149.9 руб + 13.4 за каждые 500 грамм
По 2-му магистральному поясу: 152 руб + 15.6 за каждые 500 грамм
По 3-му магистральному поясу: 158.1 руб + 15.6 за каждые 500 грамм
По 4-му магистральному поясу: 192.6 руб + 22.3 за каждые 500 грамм
По 5-му магистральному поясу: 215 руб + 36.4 за каждые 500 грамм
Эти правила действуют для посылок до 10 кг.

Страховка — 4% от объявленной стоимости посылки.

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

Вначале надо получить нужные коды типа доставки, которые прописаны в Вашей CMS.
Код типа доставки можно посмотреть в таблице [ShippingMethod]. У меня код доставки почтой России — 4, код доставки почтой России со страховкой — 5.

Поэтому для первого запуска скрипта я ставлю @shipping_code = 4, @insurance_percent = 0.
Вторым — @shipping_code = 5, @insurance_percent = 4

Есть три варианта запуска скрипта

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

Кроме областей из моего списка есть иные области России
Можно внести список областей, из моего предыдущего поста этой серии и временно или постоянно оставить в работе другие области.
Тогда надо вручную посмотреть в таблице [StateProvince] первый ID области из того списка, раскомментировать строчку /* SET @start_id = ...*/ и внести этот номер.
После этого такой скрипт точно так же можно запустить.
Важно! Список должен быть точно тем же, что и у меня, иначе настройка магистральных поясов собьётся.

У вас уже есть свой список областей, который вы не хотите менять
Устанавливаем следующей командой @start_id в 0
SET @start_id = 0

Переписываем команду INSERT INTO #zones (zone_id, zone_num ) VALUES… под свой набор областей.
Для этого смотрим таблицу [StateProvince], получаем ID областей, распределяем их по магистральным поясам согласно нижеприведенному списку и формируем SQL команду в виде
INSERT INTO #zones (zone_id , zone_num )
     VALUES
	 (110, 1) , (111,1), (112,2) , ...


Здесь первое число — ID области из таблицы [StateProvince], а второе — номер магистрального пояса.
  • 1-й магистральный пояс
    Москва, Брянская обл., Владимирская обл., Вологодская обл., Воронежская обл., Ивановская обл., Калужская обл., Костромская обл., Курская обл., Липецкая обл., Московская обл., Нижегородская, Орловская обл., Рязанская обл., Смоленская обл., Тамбовская обл., Тверская обл., Тульская обл., Ярославская обл.
  • 2-й магистральный пояс
    Санкт-Петербург, Севастополь, Адыгея, Башкортостан, Ингушетия, Кабардино-Балкария, Калмыкия, Карачаево-Черкесия, Карелия, Коми, Крым, Марий Эл, Мордовия, Северная Осетия — Алания, Татарстан, Удмуртия, Чечня, Чувашия, Краснодарский край, Пермский край, Ставропольский край, Архангельская обл., Астраханская обл., Белгородская обл., Волгоградская обл., Калининградская обл., Кировская обл., Ленинградская область, Мурманская обл., Новгородская обл., Оренбургская обл., Пензенская обл., Псковская обл., Ростовская обл., Самарская обл., Саратовская обл., Свердловская обл., Ульяновская обл., Челябинская обл., Ненецкий АО
  • 3-й магистральный пояс
    Алтай, Дагестан, Тыва (Тува), Хакасия, Алтайский край, Красноярский край, Кемеровская обл., Курганская обл., Новосибирская обл., Омская обл., Томская обл., Тюменская обл., Ханты-Мансийский АО — Югра, Ямало-Ненецкий АО
  • 4-й магистральный пояс
    Бурятия, Саха (Якутия), Забайкальский край, Амурская обл., Иркутская обл.
  • 5-й магистральный пояс
    Камчатский край, Приморский край, Хабаровский край, Магаданская обл., Сахалинская обл., Еврейская АО, Чукотский АО

Внимание! Если какие-то изменения в SQL не отображаются на сайте, необходимо нажать «Перезагрузить приложение» в админке. И не забудьте сделать бекап базы данных!

Сам скрипт:
BEGIN TRY

/* Код доставки почтой России - 4. */
DECLARE @shipping_code INT = 4
/* Стоимость страховки */
DECLARE @insurance_percent FLOAT = 0

/* Код магазина. 0 - для всех магазинов */
DECLARE @store_code INT = 0


/* Прописываем тарифы для каждого магистрального пояса */
DECLARE @base_price1 FLOAT = 149.9
DECLARE @delta_price1 FLOAT = 13.4
DECLARE @base_price2 FLOAT = 152
DECLARE @delta_price2 FLOAT = 15.6
DECLARE @base_price3 FLOAT = 158.1
DECLARE @delta_price3 FLOAT = 22.3
DECLARE @base_price4 FLOAT = 192.6
DECLARE @delta_price4 FLOAT = 31.8
DECLARE @base_price5 FLOAT = 215
DECLARE @delta_price5 FLOAT = 36.4

DECLARE @base_price FLOAT
DECLARE @delta_price FLOAT
DECLARE @i INT
DECLARE @russia_code INT
DECLARE @start_id INT
DECLARE @zone_id INT
DECLARE @zone_num INT

SELECT @russia_code = MIN (id) FROM [Country] WHERE [Name] = 'Russia'

/*  Очищаем старые данные  */
DELETE FROM [ShippingByWeight] WHERE [CountryId] = @russia_code and [ShippingMethodId] = @shipping_code

SELECT @start_id = MIN (id) FROM [StateProvince] WHERE [CountryId] = @russia_code
/* SET @start_id = ...*/

/* Создаем временную таблицу и заполняем кодами областей и соответствующими номерами магистральных поясов */
CREATE TABLE  #zones (zone_id INT, zone_num INT)

INSERT INTO #zones (zone_id , zone_num )
     VALUES
(0,1),(38,1),(39,1),(41,1),(42,1),(43,1),(46,1),(49,1),(51,1),(53,1),(55,1),(57,1),(62,1),(66,1),(71,1),(72,1),(73,1),(75,1),(79,1),
(1,2),(2,2),(3,2),(5,2),(8,2),(9,2),(10,2),(11,2),(12,2),(13,2),(14,2),(15,2),(16,2),(18,2),(19,2),(21,2),(23,2),(24,2),(28,2),(30,2),
(32,2),(35,2),(36,2),(37,2),(40,2),(45,2),(48,2),(52,2),(56,2),(58,2),(61,2),(63,2),(64,2),(65,2),(67,2),(68,2),(70,2),(77,2),(78,2),(81,2),
(4,3),(7,3),(20,3),(22,3),(25,3),(29,3),(47,3),(50,3),(59,3),(60,3),(74,3),(76,3),(82,3),(84,3),
(6,4),(17,4),(26,4),(34,4),(44,4),
(27,5),(31,5),(33,5),(54,5),(69,5),(80,5),(83,5)



/* Проходим по всей временной таблице */
DECLARE Zones_Cursor CURSOR FOR
SELECT zone_id, zone_num 
FROM #zones;
OPEN Zones_Cursor ;
FETCH NEXT FROM Zones_Cursor INTO @zone_id, @zone_num;
WHILE @@FETCH_STATUS = 0
   BEGIN
		BEGIN
			/* Определяем параметры тарифа для конкретной области */
			IF  @zone_num = 1  SET @base_price = @base_price1
			IF  @zone_num = 1  SET @delta_price = @delta_price1
			IF  @zone_num = 2  SET @base_price = @base_price2
			IF  @zone_num = 2  SET @delta_price = @delta_price2
			IF  @zone_num = 3  SET @base_price = @base_price3
			IF  @zone_num = 3  SET @delta_price = @delta_price3
			IF  @zone_num = 4  SET @base_price = @base_price4
			IF  @zone_num = 4  SET @delta_price = @delta_price4
			IF  @zone_num = 5  SET @base_price = @base_price5
			IF  @zone_num = 5  SET @delta_price = @delta_price5

			SET @i = 0
			/* Проходим по каждой половине килограмма до 10 кг */
			WHILE @i < 20
				BEGIN
					INSERT INTO [ShippingByWeight]
						([StoreId]
						,[CountryId]
						,[StateProvinceId]
						,[ShippingMethodId]
						,[From]
						,[To]
						,[AdditionalFixedCost]
						,[PercentageRateOfSubtotal]
						,[RatePerWeightUnit]
						,[LowerWeightLimit])
					VALUES (
						@store_code, 
						@russia_code, 
						@start_id + @zone_id , 
						@shipping_code, 
						@i * 500,
                                                (@i + 1) * 500 - 1,
						ROUND (@base_price + @i * @delta_price + 0.499, 0),
						@insurance_percent, 
						0, 
						0)

					SET @i = @i + 1
				END		
		END
		FETCH NEXT FROM Zones_Cursor into @zone_id, @zone_num;
	END;
CLOSE Zones_Cursor ;
DEALLOCATE Zones_Cursor ;

DROP TABLE #zones

END TRY
BEGIN CATCH 
	SELECT
        ERROR_NUMBER() AS ErrorNumber
        ,ERROR_SEVERITY() AS ErrorSeverity
        ,ERROR_STATE() AS ErrorState
        ,ERROR_LINE() AS ErrorLine
        ,ERROR_MESSAGE() AS ErrorMessage;
END CATCH;

NopCommerce и почта России. Часть 1. Прописываем области.

Часть 1. Прописываем области.
Это — первая часть серии постов, посвященная настройке CMS на основе NopCommerce для работы с почтой России.
Вносить области рекоменую этим скриптом, это избавит вас в дальнейшем с проблемами по адаптации скриптов к вашему набору областей.

Сам список областей был взят по ссылкам Субъекты Российской Федерации и Federal subjects of Russia

Внимание! Этот скрипт удаляет все предыдущие области России. В случае наличия каких-то адресов, в которых используются области, скрипт не отработает.

Сайт только первоначально настраивается
Если сайт только настраивается и еще не запущен в реальную работу. Можно просто удалить все записи в таблице [Address] или установить столбец [StateProvinceId] таблицы [Address] для всех записей в произвольное значение, например 1.

Сайт находится в работе

В это случае процедура будет сложнее.
  • Комментируем 2 инструкции удаления DELETE в разделе «Очистка старых данных»
  • Запускаем скрипт
  • Когда новые области будут созданы отдельными SQL запросами меняем ID старых областей в таблице Address на ID новых
  • Удаляем старые области из таблиц [StateProvince] и [LocalizedProperty].


Если какие-то изменения в SQL не отображаются на сайте, необходимо нажать «Перезагрузить приложение» в админке. И не забудьте сделать бекап базы данных!


BEGIN TRY

DECLARE @russia_code INT
DECLARE @language_code INT

DECLARE @start_id INT


/*  Получаем коды России и русского языка в таблицах сайта */
SELECT @russia_code = MIN (id) FROM [Country] WHERE [Name] = 'Russia'
SELECT @language_code = MIN (id) FROM [Language] WHERE [Name] = 'Russian'

/* Очистка старых данных */
DELETE FROM [LocalizedProperty] WHERE [LocaleKeyGroup] = 'StateProvince' AND [LocaleKey] = 'Name' AND [LanguageId] = @language_code 
DELETE FROM [StateProvince] WHERE [CountryId] = @russia_code 



/* Создаем временную таблицу и заполняем именами областей и ID для сортировки */

CREATE TABLE #provinces (
	P_Id INT PRIMARY KEY IDENTITY,
	sort_position INT, 
	english_name nvarchar(50), 
	russian_name nvarchar(50))


/* Создаем временную таблицу и заполняем кодами областей и соответствующими номерами магистральных поясов */
INSERT INTO #provinces (sort_position , english_name, russian_name )
	VALUES
	(1, 'Moscow', 'г. Москва'),
	(4, 'Saint Petersburg', 'г. Санкт-Петербург'),
	(7, 'Sevastopol', 'г. Севастополь'),
	(10, 'Adygea, Republic of', 'Адыгея'),
	(20, 'Altai Republic', 'Алтай'),
	(30, 'Bashkortostan, Republic of', 'Башкортостан'),
	(40, 'Buryatia, Republic of', 'Бурятия'),
	(50, 'Dagestan, Republic of', 'Дагестан'),
	(60, 'Ingushetia, Republic of', 'Ингушетия'),
	(70, 'Kabardino-Balkar Republic', 'Кабардино-Балкария'),
	(80, 'Kalmykia, Republic of', 'Калмыкия'),
	(90, 'Karachay-Cherkess Republic', 'Карачаево-Черкесия'),
	(100, 'Karelia, Republic of', 'Карелия'),
	(110, 'Komi Republic', 'Коми'),
	(120, 'Republic of Crimea', 'Крым'),
	(130, 'Mari El Republic', 'Марий Эл'),
	(140, 'Mordovia, Republic of', 'Мордовия'),
	(150, 'Sakha (Yakutia) Republic', 'Саха (Якутия)'),
	(160, 'North Ossetia-Alania, Republic of', 'Северная Осетия — Алания'),
	(170, 'Tatarstan, Republic of', 'Татарстан'),
	(180, 'Tuva Republic', 'Тыва (Тува)'),
	(190, 'Udmurt Republic', 'Удмуртия'),
	(200, 'Khakassia, Republic of', 'Хакасия'),
	(210, 'Chechen Republic', 'Чечня'),
	(220, 'Chuvash Republic', 'Чувашия'),
	(230, 'Altai Krai', 'Алтайский край'),
	(240, 'Zabaykalsky Krai', 'Забайкальский край'),
	(250, 'Kamchatka Krai', 'Камчатский край'),
	(260, 'Krasnodar Krai', 'Краснодарский край'),
	(270, 'Krasnoyarsk Krai', 'Красноярский край'),
	(280, 'Perm Krai', 'Пермский край'),
	(290, 'Primorsky Krai', 'Приморский край'),
	(300, 'Stavropol Krai', 'Ставропольский край'),
	(310, 'Khabarovsk Krai', 'Хабаровский край'),
	(320, 'Amur Oblast', 'Амурская обл.'),
	(330, 'Arkhangelsk Oblast', 'Архангельская обл.'),
	(340, 'Astrakhan Oblast', 'Астраханская обл.'),
	(350, 'Belgorod Oblast', 'Белгородская обл.'),
	(360, 'Bryansk Oblast', 'Брянская обл.'),
	(370, 'Vladimir Oblast', 'Владимирская обл.'),
	(380, 'Volgograd Oblast', 'Волгоградская обл.'),
	(390, 'Vologda Oblast', 'Вологодская обл.'),
	(400, 'Voronezh Oblast', 'Воронежская обл.'),
	(410, 'Ivanovo Oblast', 'Ивановская обл.'),
	(420, 'Irkutsk Oblast', 'Иркутская обл.'),
	(430, 'Kaliningrad Oblast', 'Калининградская обл.'),
	(440, 'Kaluga Oblast', 'Калужская обл.'),
	(450, 'Kemerovo Oblast', 'Кемеровская обл.'),
	(460, 'Kirov Oblast', 'Кировская обл.'),
	(470, 'Kostroma Oblast', 'Костромская обл.'),
	(480, 'Kurgan Oblast', 'Курганская обл.'),
	(490, 'Kursk Oblast', 'Курская обл.'),
	(500, 'Leningrad Oblast', 'Ленинградская область'),
	(510, 'Lipetsk Oblast', 'Липецкая обл.'),
	(520, 'Magadan Oblast', 'Магаданская обл.'),
	(530, 'Moscow Oblast', 'Московская обл.'),
	(540, 'Murmansk Oblast', 'Мурманская обл.'),
	(550, 'Nizhny Novgorod Oblast', 'Нижегородская обл.'),
	(560, 'Novgorod Oblast', 'Новгородская обл.'),
	(570, 'Novosibirsk Oblast', 'Новосибирская обл.'),
	(580, 'Omsk Oblast', 'Омская обл.'),
	(590, 'Orenburg Oblast', 'Оренбургская обл.'),
	(600, 'Oryol Oblast', 'Орловская обл.'),
	(610, 'Penza Oblast', 'Пензенская обл.'),
	(620, 'Pskov Oblast', 'Псковская обл.'),
	(630, 'Rostov Oblast', 'Ростовская обл.'),
	(640, 'Ryazan Oblast', 'Рязанская обл.'),
	(650, 'Samara Oblast', 'Самарская обл.'),
	(660, 'Saratov Oblast', 'Саратовская обл.'),
	(670, 'Sakhalin Oblast', 'Сахалинская обл.'),
	(680, 'Sverdlovsk Oblast', 'Свердловская обл.'),
	(690, 'Smolensk Oblast', 'Смоленская обл.'),
	(700, 'Tambov Oblast', 'Тамбовская обл.'),
	(710, 'Tver Oblast', 'Тверская обл.'),
	(720, 'Tomsk Oblast', 'Томская обл.'),
	(730, 'Tula Oblast', 'Тульская обл.'),
	(740, 'Tyumen Oblast', 'Тюменская обл.'),
	(750, 'Ulyanovsk Oblast', 'Ульяновская обл.'),
	(760, 'Chelyabinsk Oblast', 'Челябинская обл.'),
	(770, 'Yaroslavl Oblast', 'Ярославская обл.'),
	(810, 'Jewish Autonomous Oblast', 'Еврейская АО'),
	(820, 'Nenets Autonomous Okrug', 'Ненецкий  АО'),
	(830, 'Khanty–Mansi Autonomous Okrug – Yugra', 'Ханты-Мансийский АО - Югра'),
	(840, 'Chukotka Autonomous Okrug', 'Чукотский АО'),
	(850, 'Yamalo-Nenets Autonomous Okrug', 'Ямало-Ненецкий АО')

	/* Заполняем список областей */
INSERT INTO [StateProvince]
           ([CountryId]
           ,[Name]
           ,[Published]
           ,[DisplayOrder])
	SELECT    
		@russia_code, 
		english_name, 
		1, 
		sort_position   
	FROM #provinces


SET @start_id = @@IDENTITY - @@ROWCOUNT 

/* Заполняем переводы областей на русский язык*/
INSERT INTO [LocalizedProperty]
           ([EntityId]
           ,[LanguageId]
           ,[LocaleKeyGroup]
           ,[LocaleKey]
           ,[LocaleValue])
	SELECT 
		@start_id + P_ID, 
		@language_code, 
		'StateProvince', 
		'Name', 
		russian_name  
	FROM #provinces

DROP TABLE #provinces

END TRY
BEGIN CATCH 
	SELECT
        ERROR_NUMBER() AS ErrorNumber
        ,ERROR_SEVERITY() AS ErrorSeverity
        ,ERROR_STATE() AS ErrorState
        ,ERROR_LINE() AS ErrorLine
        ,ERROR_MESSAGE() AS ErrorMessage;
END CATCH;

Миграция линуксового PGP в виде Virtual Appliance.

У этого продукта есть удобная возможность сделать полный бекап и восстановление конфигурации. Это поможет мне провести миграцию с минимальным даунтаймом. Сначала мигрирую копию сервера, устанавливаю другой IP адрес, потом обновляю до актуальной конфигурации и возвращаю оригинальный IP.
Первым делом сохраняю *.vmdk на жесткий диск и конвертирую в *.vhd. Есть разные утилиты для преобразований, даже родные от Microsoft. Я сделал это с помощью бесплатной программы StarWind V2V Image Converter.
Получившийся файл PGP Server_1.vhd скопировал на локальный диск сервера Hyper-V через административный расшаренный ресурс \\servername\c$
В Hyper-V Manager создаю виртуальную машину с именем PGP и указываю использовать существующий диск.
Иду в настройки получившейся машины, удаляю Network Adapter и добавляю Legacy Network Adapter. Пока не стоит специальных драйверов можно пользоваться только этой сетевой картой. Состояние сетевой карты должно быть Not connected! Иначе при успешном старте может быть конфликт IP адресов с работающим сервером. Если работающего сервера у вас нет, можете действовать на свое усмотрение.
Запускаем…. первая ошибка.

mount: could not find filesystem '/dev/root'

setuproot: moving/dev failed: No such file or directory

switchroot: mount failed: No such file or directory
Kernel panic — not syncing: Attempted to kill init!


Это связано с тем, что диск в VmWare был типа SCSI а в HyperV стал IDE.
Значит нужно загрузиться с загрузочного диска и подправить нужные настройки.
Сразу скажу – загрузиться с дистрибутива CentOS 5.5 не получилось, выходил kernel panic. Надо брать поновее — CentOS-6.4-x86_64-bin-DVD1.iso, список серверов для скачки — isoredirect.centos.org/centos/6/isos/x86_64/

Подключаю скачанный образ CentOS 6.4 и загружаюсь в режиме восстановления, сеть подключать не обязательно. Выхожу в shell.
Первым делом, как было написано в информационных окнах во время запуска OS, запускаю #chroot /mnt/sysimage/

Дальше в двух файлах меняю sda* на hda*
— /etc/grub.conf
— /etc/fstab

Командой passwd сбрасываю рутовый пароль. Если хотите работать более безопасно, заведите еще и отдельного пользователя.
Что бы иметь возможность подключаться по ssh, в файле /etc/sshd/sshd_config параметр PasswordAuthentication меняю с no на yes.
В директории /etc/sysconfig/network-scripts/ смотрим наличие и содержимое файлов ifcfg-ethN. У меня там только один файл ifcfg-eth0. Захожу в него через vi и меняю IP на другой, что бы не было конфликта с работающим сервером. Опять же, если таковых нет, пропускайте.

Перезагружаю сервер и радостно наблюдаю успешную загрузку, прерываемую лишь неудачными стартами некоторых PGP-шных сервисов из-за смены IP. Но это не страшно, когда верну IP назад, все поднимется успешно.
Подключаю сеть и проверяю подключение по SSH.
Бинго! На этом этапе можно сохраниться, точнее заснепшотиться. Линукс, особенно без установленных integration tools, лучше снапшотить в выключенном состоянии

Создаю файл /etc/yum.repos.d/mainrepo.repo следующего содержания
[MainRepo]
name= MainRepo
baseurl=http://mirror.centos.org/centos/5/os/i386/
enabled=1
gpgcheck=0


По вечерам с этим репозиторием проблемы, поэтому можно поменять на другой.
baseurl= ftp://ftp.muug.mb.ca/mirror/centos/5/os/i386/

Тестирую
#yum clean all
#yum list

Должен выйти список компонент репозитория.

Обновляю систему. Для этого добавляю в файл /etc/yum.conf строку

exclude=centos-release-* perl-* initscripts-* openldap*
Первые три компоненты обновить с налету не получилось, дальше копать не стал. А обновленный openldap несовместим с текущей версией PGP, поэтому оставляем его старым.

Запускаю обновление
#yum update

Несмотря на формальную версию Centos 5.5, после обновления все компоненты находятся на уровне CentOS 5.9, в которой осуществлена встроенная поддержка Hyper-V

Меняю обратно в двух файлах меняю hda* на sda*
— /etc/grub.conf
— /etc/fstab

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

Смотрю в /etc/grub.conf версию новоустановленного ядра и пути к загрузочным файлам.

splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title CentOS (2.6.18-348.el5PAE)
root (hd0,0)
kernel /vmlinuz-2.6.18-348.el5PAE ro root=/dev/sda2 noexec=off
initrd /initrd-2.6.18-348.el5PAE.img
title CentOS (2.6.18-348.el5)
root (hd0,0)
kernel /vmlinuz-2.6.18-348.el5 ro root=/dev/sda2 noexec=off
initrd /initrd-2.6.18-348.el5.img


Включаю модули поддержки виртуализации
#mkinitrd /boot/initrd-2.6.18-348.el5PAE.img 2.6.18-348.el5PAE --preload hv_storvsc --preload hv_vmbus --preload hv_utils --preload hv_netvsc --preload hid-hyperv --preload hid-base-hv -f
#mkinitrd /boot/initrd-2.6.18-348.el5.img 2.6.18-348.el5 --preload hv_storvsc --preload hv_vmbus --preload hv_utils --preload hv_netvsc --preload hid-hyperv --preload hid-base-hv -f

#shutdown –h now

Удаляю устаревший сетевой адаптер и добавляю обычный.

После включения проверяю успешную загрузку модулей командой
#lsmod | grep hv

После успешной загрузки и проверки бекаплю работающий PGP, ставлю на новом IP старого и восстанавливаю бекап.
Даунтайм около 2-х минут.

DNS провайдера

Всегда недолюбливал настройку DNS серверов таким образом, что бы форвардить все запросы провайдеру.
И сегодня столкнулся с реальной проблемой из-за такой конфигурации в одной из моих сетей.
Вчера вечером изменил DNS сервера основной зоны, прописал новые сервера у регистратора и начал ждать, когда все изменения пропихнутся.
На большинство площадок новые DNS пришли достаточно быстро, на самой последней спустя сутки все резолвилось по старому.
Расследование показало, что на этой площадке стоял форвардинг запросов провайдеру на 3 DNS, два последних из них отдавали зону правильно, а третий нет.
Оказалось, что он самовольно подменяет TTL NS-записей всех зон, которые отдает. Т.е., изменения всех DNS серверов к нам приходят с огромной задержкой. В 4 дня!
Возьмем для примера ya.ru.

nslookup -d2 -type=soa ya.ru. ns.dolbonet.ru

Non-authoritative answer:
ya.ru
type = SOA, class = IN, dlen = 44
ttl = 7200 (2 hours)
primary name server = ns1.yandex.ru
responsible mail addr = sysadmin.yandex.ru
serial = 2012103000
refresh = 10800 (3 hours)
retry = 900 (15 mins)
expire = 2592000 (30 days)
default TTL = 900 (15 mins)

ya.ru
type = NS, class = IN, dlen = 6
nameserver = ns5.yandex.ru
ttl = 344602 (3 days 23 hours 43 mins 22 secs)
ya.ru
type = NS, class = IN, dlen = 2
nameserver = ns1.yandex.ru
ttl = 344602 (3 days 23 hours 43 mins 22 secs)
ns5.yandex.ru
type = A, class = IN, dlen = 4
internet address = 213.180.204.1
ttl = 167578 (1 day 22 hours 32 mins 58 secs)
ns1.yandex.ru
type = A, class = IN, dlen = 4
internet address = 213.180.193.1
ttl = 141968 (1 day 15 hours 26 mins 8 secs)
ns1.yandex.ru
type = AAAA, class = IN, dlen = 16
AAAA IPv6 address = 2a02:6b8::1
ttl = 3140 (52 mins 20 secs)
сравним с честной отдачей родных DNS серверов

nslookup -d2 -type=soa ya.ru. ns1.yandex.ru.

ya.ru
type = SOA, class = IN, dlen = 44
ttl = 7200 (2 hours)
primary name server = ns1.yandex.ru
responsible mail addr = sysadmin.yandex.ru
serial = 2012103000
refresh = 10800 (3 hours)
retry = 900 (15 mins)
expire = 2592000 (30 days)
default TTL = 900 (15 mins)
ya.ru
type = NS, class = IN, dlen = 6
nameserver = ns5.yandex.ru
ttl = 7200 (2 hours)
ya.ru
type = NS, class = IN, dlen = 2
nameserver = ns1.yandex.ru
ttl = 7200 (2 hours)
ns1.yandex.ru
type = A, class = IN, dlen = 4
internet address = 213.180.193.1
ttl = 345600 (4 days)
ns1.yandex.ru
type = AAAA, class = IN, dlen = 16
AAAA IPv6 address = 2a02:6b8::1
ttl = 3600 (1 hour)
ns5.yandex.ru
type = A, class = IN, dlen = 4
internet address = 213.180.204.1
ttl = 345600 (4 days)

Не всякий админ будет держать старые DNS четыре дня. Причем, иногда их держать технически невозможно. Да, и если провайдер так самовольно распоряжается NS-записями, он может и TTL А-записей переправлять. А это уже намного опаснее.