2020-12-22
W artykule
Azure: zdalna zmiana rejestru w celu zmiany opcji połączeń zdalnych
opisałem, jak zmodyfikować rejestr maszyny wirtualnej znajdującej się w Azure, w celu odblokowania możliwości połączenia do tej maszyny z komputerów bez uwierzytelnienia klienta. Z czasem jednak, ta metoda delikatnie się zmieniła. Teraz nie można już załadować bezpośrednio pliku skryptu do uruchomienia, tylko trzeba ten plik wybrać ze storage account. Dochodzi więc jeden dodatkowy krok – stworzenie storage account i przegranie tam pliku skryptu.
tak wygląda początkowe okno pobierania skryptu „extension”

Po kliknięciu „browse” należy wybrać storage account. Zakładając, że go nie masz, trzeba kliknąć „+Storage account”

Tutaj tworzysz storage account – najważniejsze to wymyślić unikalną nazwę i wybrać inne parametry – celuj w te tańsze 🙂

Dzięki temu można już wybrać storage account, ale…

jest on pusty. Trzeba najpierw założyć container. W tym celu kliknij „+Container”

Ten kontener można wybrać, ale…

… jeszcze nie ma na nim plików (skryptów), dlatego można kliknąć „upload” i załadować skrypt extension.

Ten skrypt należy następnie wybrać i taddam – jesteśmy w sumie w tym samym miejscu, co w poprzednim artykule!

Niestety takie ciagłe zmiany w Azure, to coś do czego musimy przywyknąć.
2020-12-22
Podczas odtwarzania bazy danych przy pomocy narzędzia Tivoli Data Protection pojawil się komunikat:
Failed – Error: RC: 1914
ACO5422E Received the following from the MS SQL server: Could not load file or assembly ‚Microsoft.SqlServer.Smo, Version=12.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91’ or one of its dependencies. The system cannot find the file specified
No dobrze, ale to jakiego pliku konkretnie brakuje? Pliku wrpawdzie w komunikacie nie ma ale za to jest nazwa pbrakującego pakietu. Dobre i to! Smo to Shared Management Objects. SMO wchodzi w sklad pakietu SQL Features Pack wydawanego osobno dla kazdej wersji SQL. Komunikat mowi o wersji 12, czyli zgodnie z numeracją Mocrosoft SQL 2014. Można go pobrać stąd:
https://www.microsoft.com/en-us/download/details.aspx?id=42295
Ale i tak coś mi tu jeszcze spokoju nie daje. SQL na którym pracuję to SQL 2016. Baza, którą odtwarzam to 2012. Dlaczego mam instalować SMO 2014? Nie chcę śmiecić na serwerze z SQL 2016 instalajami z 2014. Dlatego zacząlem od 2016. Nie pomoglo. Potem zainstalowlem 2012. Nie pomoglo. No to w koncu uzylem 2014 – bingo! Na cale szczescie restarty nie byly potrzebne
Maly pakiet – 6-7 MB, a dal pomyśleć!
2020-12-18
Niektóre aplikacje wymagają ustawienia zmiennych środowiskowych. W command line to nie problem:
i gotowe! Jednak coraz częściej to PowerShell jest domyślnym shellem. Jak więc ustawić zmienną środowiskową w PowerShell?
|
[System.Environment]::SetEnvironmentVariable('FLASK_DEBUG', '1',[System.EnvironmentVariableTarget]::Process) |
Nie jest to zbyt proste, ale:
- [SystemEnvironment] pozwala odwołać się do programistycznej klasy, która odpowiada za zarządzanie środowiskiem
- SetEnvironmentVariable – to metoda statyczna w/w klasy, która odpowiada za ustawienie zmiennej środowiskowej
- pierwszy argument to nazwa zmiennej
- drugi argument to jej wartość
- trzeci argument określa zakres widoczności zmiennej. Mamy do wyboru Machine, User albo Process. Process stworzy zmienną tylko na skalę tego jednego procesu i jego procesów potomnych
Jak więc widać… trochę to bardziej skomplikowane. Dla uzupełnienia powiedzmy jeszcze jak ustawić zmienną środowiskową w BASH:
|
FLASK_DEBUG=1 export FLASK_DEBUG |
Sprawdzenie zmiennych środowiskowych:
command line:
PowerShell
BASH
2020-12-09
Załóżmy, że mamy listę portów lotniczych i zastanawiamy się, jakie można zbudować trasy między nimi:
|
ports = ['WAW', 'KRK', 'GDN', 'KTW', 'WMI', 'WRO', 'POZ', 'RZE', 'SZZ', 'LUZ', 'BZG', 'LCJ', 'SZY', 'IEG', 'RDO'] routes = [ (start, stop) for start in ports for stop in ports] print(routes) print(len(routes)) |
W routes zostanie wygenerowanych 255 tras, ale niestety znajdą się w niej zbędne wartości. Będzie trasa WAW-WAW, ale znajdą się też duplikaty WAW-KRK oraz KRK-WAW. Jak je wykluczyć? Zmieniając wyrażenie generujące wartości dostaniemy już tylko 210 wyników, ale wyeliminowaliśmy tylko trasy z tego samego miasta do tego samego miasta:
|
routes = [ (start, stop) for start in ports for stop in ports if start != stop] print(routes) print(len(routes)) |
No to idźmy dalej. Polecenie w tej postaci da o wiele lepszy wynik – 105 tras:
|
routes = [ (start, stop) for start in ports for stop in ports if start < stop] print(routes) print(len(routes)) |
Zapis start<stop jest nieco dziwny. Porównujemy napisy: A<B, B<C, C<D itd. Tak jak lista obecności w dzienniku szkolnym. Ten znak ostrej nierówności to „sztuczka programistyczna”. Skoro A jest mniejsze od B, to nasz wzór wykryje tylko połączenie A do B, ale połączenie B do A pominie, bo B nie jest mniejsze od A.
Programowanie to nie tylko instrukcje i kod. Programowanie to też sztuczki, które sprawiają, że ten sam problem da się rozwiązać na kilka(set) różnych sposobów – a my musimy tylko wybrać ten lepszy z pewnego punktu widzenia!
2020-12-09
Wyrażenia logiczne w Pythonie są wyznaczane od lewej do prawej. Jeśli więc masz w if wyrażenie logiczne expr1 and expr2, to expr2 będzie wyliczane tylko wtedy jeśli expr1 ma wartość True. Jest to całkiem oczywiste z punktu widzenia optymalizacji liczby wykonywanych obliczeń – gdyby expr1 już miało wartość False, to nie ma sensu wyliczać wartości dla expr2, bo ostateczna wartość dla expr1 and expr2 to False!
Jednak informacja o kolejności wyznaczania wartości jest istotna. Popatrz na ten przykład:
|
i = 0 box = ['ab','bcd','cde'] while len(box[i])>0 and i < len(box): print(box[i]) i += 1 |
Uruchomienie skryptu skończy się błędem
IndexError: list index out of range
Dlaczego? Bo w pewnym momencie i będzie wynosiło 3 i odwołanie do box[i] nie ma sensu. Jeśli jednak zmieni się kolejność warunków w while:
|
i = 0 box = ['ab','bcd','cde'] while i < len(box) and len(box[i])>0: print(box[i]) i += 1 |
To nim odwołamy się do box[i], najpierw odbędzie się sprawdzenie, czy i<len(box). To wyrażenie zwróci wartość False, a co za tym idzie nie odbędzie się obliczanie dla prawej części wyrażenia and.
Sprytne!
2020-11-15
Postgres pozwala zdefiniować progi wybranych liczników, po przekroczeniu których, aktywność użytkownika może być usunięta z serwera. Kilka z nich to:
- deadlock_timeout – czas po jakim zapytanie oczekujące na zwolnienie deadlock ma się „poddać”. Domyślna wartość to 1000 ms. Użytkownik może przedefiniować ten parametr
- statement_timeout – czas po jakim długo wykonujące się polecenie ma się przerwać. Można je ustawić globalnie lub dla wybranej funkcji. Domyślna wartość zero oznacza, że takiego limitu nie ma
- lock_timeout – czas po jakim długo trwające oczekiwanie na lock ma się przerwać. Ponieważ update statements muszą w pierwszej kolejności uzyskać lock na modyfikowanych rekordach, to lock_timeout powienien być mniejszy niż statement_timeout. Domyślnie ta wartość wynosi zero, co znaczy, że czekanie odbywa się bez limitu. Parametr ustawia się na sesję lub dla funkcji.
- idle_in_transaction_session_timeout – maksymalny czas, przez jaki może trwać transakcja nie podejmując żadnych nowych czynności. Jeśli ten czas zostanie przekroczony, to transakcja zostanie wycofana. Domyślna wartość zer określa, że nie ma żadnego limitu.
Technicznie zmiana parametru jest wykonywana poleceniem
|
SET configuration_parameter TO values; |
Jeśli więc jedna sesja wykonała polecenie:
|
START TRANSACTION; DELETE FROM rental WHERE rental_id=2 |
a druga wykona:
|
START TRANSACTION; SET lock_timeout TO 5000; UPDATE rental SET last_update = NOW() WHERE rental_id = 2 |
to po ok. 5 sekundach otrzymasz błąd w sesji drugiej:
ERROR: canceling statement due to lock timeout
CONTEXT: while locking tuple (0,1) in relation „rental”
SQL state: 55P03
Aby przywrócić oryginalną wartość parametru wystarczy wykonać:
|
SET lock_timeout TO values; |
2020-11-08
Jednym z zadań administratora jest obserwacja aktywności użytkowników i w skrajnych przypadkach przerwanie niepoprawnych lub zbyt intensywnych zapytań.
Sprawdzenie aktywności można wykonać poleceniem
|
SELECT * FROM pg_stat_activity; |
W odpowiedzi zostanie zwrócony data set zawierający informacje o tym kto i co w danej chwili robi na serwerze:
Czytaj dalej »