Wielka promocja ebooków – wybór – do 20 maja

Na ebookpoint jest fajna promocja. Poniżej wybór książek które wydają się ciekawe. Pogrubione to te, które moim zdaniem każdy programista powinien przeczytać.

Przetwarzanie równoległe i wielkoskalowe

Architektura, wzorce i dobre praktyki

JavaScript

 

Tajniki języka JavaScript – Kyle Simpson

Miękkie

Różności

Offtop

Konfiguracja Vault Hashicorp: Wstęp i uruchomienie wersji rozwojowej

Wstęp i uruchomienie

W pracy pojawił się problem współdzielenia kilku haseł pomiędzy programistami i ich aktualizacji. Najciekawszym rozwiązaniem tego problemu jest użycie programu Vault firmy HashiCorp. Do funkcji które zwróciły moją uwagę należą kontrola i logowanie dostępu, zarządzanie uprawnieniami, prosta integracja z LDAP oraz dostępne REST API.

Wszystkie kroki wykonywane są na systemie Windows10 z GitBash, jednak pomijając detale powinny działać na innych sytemach

W celu uruchomienia aplikacji należy pobrać paczkę (https://www.vaultproject.io/downloads.html)  i wypakować plik wykonywalny.

Dla wygody, przeniosłem go do program files:

mkdir C:\Program Files\HashiCorp
mkdir C:\Program Files\HashiCorp\Vault
mv vault.exe "C:\Program Files\HashiCorp"

Plik wykonywalny dodałem do ścieżki systemowej, dodatkowo warto dodać wartość VAULT_ADDR:

Żeby sprawdzić czy wszytko jest dobrze otwieramy nową linię komend i wpisujemy:

$ vault –h

Jeśli wszytko się udało powinniśmy uzyskać podstawowe informacje o składni:

$ vault -h
Usage: vault <command> [args]

Common commands:
    read        Read data and retrieves secrets
    write       Write data, configuration, and secrets
    delete      Delete secrets and configuration
    list        List data or secrets
    login       Authenticate locally
    server      Start a Vault server
    status      Print seal and HA status
    unwrap      Unwrap a wrapped secret

Other commands:
    audit          Interact with audit devices
    auth           Interact with auth methods
    lease          Interact with leases
    operator       Perform operator-specific tasks
    path-help      Retrieve API help for paths
    policy         Interact with policies
    secrets        Interact with secrets engines
    ssh            Initiate an SSH session
    token          Interact with tokens

Uruchomienie

Żeby uruchomić Vault w wersji developerskiej należy wydać polecenie:
Takiej konfiguracji nie należy używać na produkcji

$ vault server -dev -log-level=trace

Po jego wykonaniu powinny pojawić inforamcje o konfiguracji (z ważnych rzeczy root token i adres pod którym znajdziemy REST API) oraz logi

$ vault server -dev -log-level=trace
==> Vault server configuration:

                     Cgo: disabled
         Cluster Address: https://127.0.0.1:8201
              Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", tls: "disabled")
               Log Level: trace
                   Mlock: supported: false, enabled: false
        Redirect Address: <strong>http://127.0.0.1:8200</strong>
                 Storage: inmem
                 Version: Vault v0.9.6
             Version Sha: 7e1fbde40afee241f81ef08700e7987d86fc7242

WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
and starts unsealed with a single unseal key. The root token is already
authenticated to the CLI, so you can immediately begin using Vault.

You may need to set the following environment variable:

    $ set VAULT_ADDR=http://127.0.0.1:8200

The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.

Unseal Key: xSzRUrmkIB4SeiPSW1sdpMhO2XB4BhKybJwydW6H6Bk=
Root Token: <strong>3d6c5024-21f4-a464-1db6-6cf17fd7f76a</strong>

Development mode should NOT be used in production installations!

==> Vault server started! Log data will stream in below:


================= LOGI ==========================

Zapytania za pomocą REST API możemy wykonywać domyślnie pod adresem http://127.0.0.1:8200. Polecem do tego POSTMANA, jednak na potrzeby artykułu będę używał curla, ponieważ łatwiej jest prezentować komunikację po HTTP. W celu sprawdzenia czy działa silnik działa wykonujemy poniższe zapytanie:

$ curl -s http://127.0.0.1:8200/v1/sys/init

Jeśli wszytko jest dobrze powinniśmy otrzymać:

$ curl -s http://127.0.0.1:8200/v1/sys/init
{"initialized":true}

Root Token możemy znaleźć w informacjach wyświetlonych przez serwer po uruchomieniu (Uruchomienie serwera w konfiguracji deweloperskiej – wynik). Ponieważ będzie on nam potrzebny go do zmiennej:
Przed wykonaniem komendy podmień ciąg <Twój token> na własny root token.

export VAULT_TOKEN="<Twój token>"

W celu utworzenia sekretu wykonujemy nastepujące zapytanie:

curl \
-s \
--header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data '{"naszKlucz": "naszawartosc"}' \
http://127.0.0.1:8200/v1/secret/hello

W celu odczytania możemy użyć nastepującej komendy:

curl \
-s \
--header "X-Vault-Token: $VAULT_TOKEN" \
http://127.0.0.1:8200/v1/secret/hello

Co zwróci nam pary klucz-wartość umieszczone w sekrecie oraz kilka dodatkowych informacji:

$ curl -s --header "X-Vault-Token: $VAULT_TOKEN" http://127.0.0.1:8200/v1/secret/hello
{"request_id":"2cce8a90-ffa5-b257-bcbe-fb72368cf706","lease_id":"","renewable":false,"lease_duration":2764800,"data":{"naszKlucz":"naszawartosc"},"wrap_info":null,"warnings":null,"auth":null}

W tym momencie jesteśmy w stanie współdzielić rózne sekrety, jednak są one praktycznie niezabezpieczone, ponieważ musimy udostępnić token roota który posiada najwyższe uprawnienia w aplikacji. W następnym wpise skonfiguruję autoryzację za pomocą LDAP.

Osobne connectionString dla każdego użytkownika

Wstęp

Jedna baza na programistę jest ogólnie akceptowanym standardem. Niestety nie zawsze możemy doprowadzić do sytuacji, gdzie jedna definicja połączeń do instancji będzie odpowiadała każdemu programiście.

Rozwiązaniem tego problemu jest posiadanie przez każdego użytkownika własnego zestawu definicji połączeń.

Wydzielenie folderu na definicje

  1. Tworzymy folder ConnectionConfigurations
  2. Tworzymy plik: ConnectionConfigurations/ConnectionConfiguration.config
  3. Wycinamy nasze definicje połączeń z Web.config i wklejamy je po drugiej linii nowego pliku
  4. Po tych operacjach nasz plik powinien wyglądać następująco:
    <connectionStrings>
       <clear/>
       <!-- Tu wklejamy definicje -->
       <add name="ConnName" connectionString="ConnStr" />
    </connectionStrings>
    
  5. Teraz w Web.config dodajemy linijke 3:
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <connectionStrings configSource="ConnectionConfigurations/ConnectionConfiguration.config" />
    </configuration>
    
  6. Na tym etapie mamy już wydzielone definicje połączeń do osobnego pliku. Teraz powinniśmy sprawdzić, czy nasza aplikacja się buduje. Jeśli tak przechodzimy do następnej sekcji.

Konfiguracja domyślna

  1. Na początek zmieniamy nazwę ConnectionConfiguration.config na ConnectionConfiguration.default.config
  2. Następnie otwieramy właściwości naszego projektu z plikiem Web.config i przechodzimy do zakładki Build Events
  3. W oknie zatytułowanym Pre-build event command line wprowadzamy następującą komendę:
    if exist $(ProjectDir)ConnectionConfigurations\ConnectionConfiguration.default.config (echo f|xcopy /Y $(ProjectDir)ConnectionConfigurations\ConnectionConfiguration.default.config $(ProjectDir)ConnectionConfigurations\ConnectionConfiguration.config)
    

    Linijka służy do skopiowani domyślnej konfiguracji:

    • Warunek if sprawdza czy plik istnieje, i jeśli tak, wykonywana jest komenda kopiująca
    • Xcopy odpowiada za skopianie pliku ze ścieżki źródłowej do docelowej
    • Parametr f, przekazany przez echo, informuje że kopiowany będzie plik
    • Flaga /Y wyłącza pytanie o nadpisanie pliku
    • $(ProjectDir) to makro zwracające ścieżkę głównego folderu aktualnego projektu
  4. Teraz sprawdzamy czy projekt się buduje. Jeśli tak, a projekt po uruchomieniu działa poprawnie przechodzimy dalej.

Osobna konfiguracja dla każdego użytkownika

  1. Tworzymy nowy plik ConnectionConfigurations\ConnectionConfiguration..config, np.: ConnectionConfigurations\ConnectionConfiguration.rafal.config. Powinien on wyglądać jak onnectionConfiguration.default.config, ale zawierać dogodne dla nas definicje połączeń
  2. Nastepnie w Pre-build event command line dodajemy po naszym wpisie kolejną linijkę o następującej treści:

    if  $(ConfigurationName) == Debug (if exist $(ProjectDir)ConnectionConfigurations\ConnectionConfiguration.$(username).config (echo f|xcopy /Y $(ProjectDir)ConnectionConfigurations\ConnectionConfiguration.$(username).config $(ProjectDir)ConnectionConfigurations\ConnectionConfiguration.config))
    
  3. W tym wypadku mamy zagnieżdżonego ifa – niestety nie udało mi się wymusić operacji oraz.

    • Pierwszy if sprawdza czy jesteśmy w Debug – szybkie obejście, żeby nie publikować własnych połączeń na serwery
    • Makro $(username) pobiera aktualną nazwę użytkownika.
    • Komendy wykonują się kolejno, więc jeśli jakiś użytkownik ma swój plik, jego zmiany nadpiszą konfigurację domyślną
  4. Sprawdź czy działa – jeśli tak jesteśmy w domu

Na koniec dodam, że główną inspiracją był ten post.

Z TFS do GIT w 10 minut

Każdy kto spróbował pracy z git flow nie ma ochoty wracać do odpowiednika z Microsoftu. Jednak w wypadku starszych projektów szkoda stracić historię zmian. Poniżej szybki przewodnik jak to zrobić.

Pobieramy GitTf:

A następnie rozpakowujemy go do wybranego folderu.

Tworzymy lokalne repozytorium:

  1. Otwieramy systemową linię komend i przechodzimy do folderu z plikiem git-tf.cmd
  2. Komenda do sklonowania repozytorium wygląda następująco:
    git-tf clone <span style="color: #ff0000;"><NazwaKolekcji></span> "$/<span style="color: #339966;"><NazwaBrancha></span>" --deep
    

    Obie  nazwy można wyciągnąć z linku do TFS: <nazwa_serwera>/ToolsCollection/<NazwaProjektu>

Idziemy na kawę*

Zakończenie

  1. Wchodzimy do folderu <NazwaProjektu>
  2. Otwieramy gitBash
  3. Pozytywnie puszujemy na serwer

Podpatrzone stąd
*Nie wliczamy do tytułowych 10 min

Zagwozdka z LINQ to SQL

Cześć,

ostatnio spędziłem dłuższy czas głowiąc się nad tym, dlaczego pętla w linii 23 nie aktualizuje wartości na liście:

public List<VM> Foo(IDomainContext ctx)
{
   var result = new List<VM>();
   foreach(var oneOfReportedMonths in monthsToReport)
   {
      var reports =
      _ctx.Items<reports>()
         .Where(x => IsConditionPassed(x,oneOfReportedMonths))
         .GroupBy(x => x.Id)
         .Select(x => new
         {
            Id = x.Key,
            Value = x.Sum(y => y.SubValue)
         }).ToList();
   
      var otherReports = 
      _ctx.Items<OtherReport>()
         .Select(x => new VM()
         {
            Id = x.Id,
         });

      foreach (var item in otherReports)
      {
         var P1 = reports
             .FirstOrDefault(x => x.Id == item.Id)?.Value ?? 0;
      }
      result.AddRange(otherReports);
   }
   return result;
}
Rozwiązanie było banalne:
Do poczytania:

Prawie integracja Visual Studio z Git Bash w 3 min

Cześć,

Z pewnością wielu z was używa GIT i Visual Studio. Niezależnie od integracji dostarczanej od MS, musimy czasem użyć GIT Bash (albo robimy to regularnie 🙂 ). Poniżej przyjemny sposób na szybkie otwieranie konsoli w katalogu solucji.

  1. Z menu Tools wybieramy opcję External Tools
  2. Wciskamy przycisk Add
  3. Uzupełniamy dostępne pola:
    1. Title – Wybrany przez nas tytuł. Będzie widoczny w menu
    2. Command – podajemy ścieżkę do aplikacji git-bash.exe
    3. Arguments – Pozostawiamy puste
    4. Initial directory – Z menu po prawo wybieramy Solution Directory
  4. Wciskamy Ok
  5. Od teraz możemy otwierać git-bash wybierając tytuł komendy z menu Tools

Oczywiście najwygodniejszą opcją będzie przypięcie narzędzia do skrótu klawiaturowego lub własnego paska narzędziowego (Add Commands…/Tools/External Tool <numer zależny od pozycji w menu>).

Rozwiązanie nie jest idealne i w najbliższym czasie będę szukał integracji w formie konsoli dostępnej jako ono wewnątrz VS.

Sztuczka podpatrzona jest stąd.

Pozdrawiam
Rafał

 

Co zrobić gdy pracowaliśmy na złej gałęzi

TL;DR - kliknij aby rozwinąć

 

Cześć,

bardzo się cieszę, że odwiedziłeś mój blog. Chiałbym Ci opowiedzieć o problemie jaki miałem w pracy, oraz o tym jak go rozwiązałem.

Otóż,po paru godzinach zorientowałem się, że zmiany wprowadzałem na złej gałęzi. Niestety, kiedy próbowałem zmienić ją na właściwą otrzymałem znane wielu osobom ostrzeżenie:

~/Documents/GitTest (master)
$ git checkout dev
error: Your local changes to the following files would be overwritten by checkout:
 index.html
Please commit your changes or stash them before you switch branches.
Aborting

Jego powodem jest to, że gałęzie aktualna i ta na którą próbujemy się przełączyć są niezgodne, a zmiana jednej na drugą mogła by spowodować problemy.  Żeby pokazać Ci dlaczego tak się dzieje i jak to naprawić stworzyłem syntetyczny przypadek:

Na początek tworzymy prosty plik html:

<html>
<head></head>
<body>
Wersja pierwsza
</body>
</html>

oraz nowe repozytorium GIT z jednym commitem:

 ~/Documents/GitStash (master)
$ git init
Initialized empty Git repository in C:/Users/user/Documents/GitStash/.git/

 ~/Documents/GitStash (master)
$ git add *

 ~/Documents/GitStash (master)
$ git commit -m firstCommit
[master (root-commit) 8b7de5c] firstCommit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 index.html

Teraz zrobimy sobie drugi branch, na którym będziemy rozwijali naszą stronę:

 ~/Documents/GitStash (master)
$ git branch develop
 ~/Documents/GitStash (master)
$ git checkout develop
 ~/Documents/GitStash (develop)

Kolejnym krokiem jest zmiana pliku:

<html>
<head></head>
<body>
Wersja z gałęzi test
</body>
</html>

Teraz robimy commit i wracamy na gałąź master:

 ~/Documents/GitStash (develop)
$ git commit -a -m testVersion
[test 47e6549] secondVersionOfPage
 1 file changed, 7 insertions(+)
 ~/Documents/GitStash (develop)
$ git checkout master
 ~/Documents/GitStash (develop)

Znowu zmieniamy index.html:


<html>
<head></head>
<body>
Wersja z którą chcemy mieć w develop
</body>
</html>

Teraz jeśli spróbujemy zmienić aktualna gałąź dostaniemy błąd podobny do tego z początku postu:

$ git checkout develop
error: Your local changes to the following files would be overwritten by checkout:
        index.html
Please commit your changes or stash them before you switch branches.
Aborting

Na szczęście GIT daje nam dwa wyjścia. Pierwsze to git commit, a drugie to git stash.

Komenda git commit odpada, niestety potrzebujemy tych zmian w innej gałezi. Natomiast git stash może nam pomóc.

Polecenie git stash umieszcza aktualne zmiany w schowku. Jak działa pokażę Ci poniżej. Najpierw jednak zajrzyjmy jakie mamy zamiany w kodzie:

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   index.html

no changes added to commit (use "git add" and/or "git commit -a")

Jak widzimy jest jeden zmieniony plik. Skoro wiemy co się dzieje przejdziemy do rozwiązania problemu. W tym celu użyjemy polecenia git stash:

$ git stash
Saved working directory and index state WIP on master: 0863480 InitialCommit
HEAD is now at 0863480 InitialCommit
$ git status
On branch master
nothing to commit, working tree clean

Jak widzimy z komendy status, nie ma żadnych zmian. To samo potwierdza szybki rzut oka na kod:

<html>
<head></head>
<body>
Wersja pierwsza
</body>
</html>

Gdzie w takim razie podziały się nasze zmiany? Są w schowku! Żeby pokazać co w nim jest użyjemy komendy git stash list:

$ git stash list
stash@{0}: WIP on master: 0863480 InitialCommit

Jak widzimy jest tam jedna zmiana, którą możemy odzyskać w każdej chwili. Na razie jednak jest nam to niepotrzebne, ponieważ chcemy przejść do gałęzi develop:

$ git checkout develop
Switched to branch 'develop'

Udaje się to bez problemów. Pytaniem jest, jak możemy teraz odzyskać dane? Używamy komendy git stash apply, która użyje ostatnich zmian odłożonych do schowka:

$ git stash apply
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html

Teraz wystarczy spojrzeć do kodu,

<html>
<head></head>
<body>
<<<<<<< Updated upstream Wersja z gałęzi develop ======= Wersja z która powinna być w gałęzi develop >>>>>>> Stashed changes
</body>
</html>

scalić wersje,

<html>
<head></head>
<body>
Wersja z która powinna być  w gałęzi  develop
</body>
</html>

i zrobić commit.

$ git commit -a -m secondDevelopCommit
[develop 74a8680] secondDevelopCommit
 1 file changed, 4 insertions(+)

Na koniec sprzątamy. W tym celu usuniemy zestaw zmian ostatnio dodany do schowka:

$ git stash list
stash@{0}: WIP on master: 9b7d3dc initialCommit

$ git stash drop
Dropped refs/stash@{0} (f7783d7bea969d85e294823d593535b79f89c207)

$ git stash list

Jak widzisz po poleceniu git stash drop usunięty został ostatnio dodany zestaw zmian.

W ten sposób szybko i bezboleśnie możesz przerzucić niezacommitowane zmiany ze złego brancha do dobrego.

Mam nadzieję, że moja notka będzie dla Ciebie przydatna. W normalnych warunkach nie powinieneś mieć potrzeby jej użyć, ale nie ma błędu którego nie da się popełnić.

Pozdrawiam
Rafał Karwat