poniedziałek, 9 grudnia 2024

Postgres - najprostszy backup/restore

Backup, czy raczej dump

pg_dump -U user_name db_name > db_name.sql

gdzie db_name.sql może być dowolną nazwą pliku.

Backup (dump) z kontenera

docker exec -t postgresCont pg_dump -U user_name db_name > db_name.sql

gdzie db_name.sql może być dowolną nazwą pliku, a postgresCont nazwą kontenera z postgresem.

Przywrócenie zrzutu

psql -U user_name db_name < db_name.sql

gdzie db_name.sql może być dowolną nazwą pliku.

Przywrócenie zrzutu do kontenera

docker exec -i postgresCont psql -U postgres -d yourdatabase < /path/to/your/file_with_data.sql


Przy okazji login do konsoli

psql -U user_name db_name

piątek, 25 października 2024

Prisma ORM - flow

Produkcja migracji

prisma migrate dev --name my_name_of_this_migration


Wypchnięcie wszystkich migracji do bazy danych

npx prisma migrate deploy


Aktualizacja wygenerowanego klienta Prismy

npx prisma generate

środa, 23 października 2024

Postgres - błąd o równoległej autoryzacji

Załóżmy, że chcesz podłączyć się tak do bazy danych:

psql --dbname=test_db --username=test_user --password

ale otrzymasz błąd

psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: KATASTROFALNY:  Równoległa autoryzacja nie powiodła się dla użytkownika "test_user"

Rozwiązanie

Odszukaj plik pg_hba.conf dla twojej instalacji PostgreSQL

sudo find / -name "pg_hba.conf" 2>/dev/null

Wyedytuj ten plik

sudo vim /etc/postgresql/[wersja]/main/pg_hba.conf

Znajdziesz tam linię dotyczącą lokalnych połączeń. Prawdopodobnie wygląda ona tak:

local   all             test_user                                   peer

Zmień ją na

local   all             test_user                                   trust

i zrestartuj server

sudo systemctl restart postgresql

Tworzenie aplikacji Next.js, Postgres, Prisma i deploy na platformie Vercel

Aparte na opisie z How to Build a Fullstack App with Next.js, Prisma, and Vercel Postgres

Tworzę aplikację Next.js o nazwie next-test

npx create-next-app@latest next-test

Zatwierdzam wszystkie parametry domyślne
Uzupełnić .gitignore i można sobie uruchomić aplikację, aby sprawdzić czy wszystko działa

npm run dev

Teraz należy przesłać repozytorium do Github
git push origin main 

Utworzyć aplikację na Vercel o nnazwie, najlepiej takiej jak utworzona, czyli w naszym przypadku next-test. Utworzenie aplikacji na Vercel sprowadza się do nadania jej w Github uprawnienia dla portalu Vercel.

W projekcie Vercel kliknąć zakładkę Storage i utworzyć bazę danych Postgres. Utworzoną bazę przypisać do projektu. Podczas tego procesu powstanie szereg zmiennych środowiskowych opisujących bazę Postgres

Teraz czas na instalację CLI Vercel:

npm i -g vercel@latest

Gdy się wszystko zainstaluje ściągamy utworzone wcześniej zmienne środowiskowe do lokalnego pliku .env, ale przedtem linkujemy się do projektu

Czyli linkowanie:

vercel link

A potem ściągnięcie zmiennych środowiskowych

vercel env pull .env

Warto umieścić zapis .env* w pliku .gitignore

Instalujemy pakiet Prisma:


npm install prisma --save-dev

Tworzymy folder prisma, a w nim plik schema.prisma

mkdir prisma && touch prisma/schema.prisma

W pliku schema.prisma umieszczamy przykładowy kod

// schema.prisma

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url = env("POSTGRES_PRISMA_URL") // uses connection pooling
  directUrl = env("POSTGRES_URL_NON_POOLING") // uses a direct connection
}

model Post {
  id        String     @default(cuid()) @id
  title     String
  content   String?
  published Boolean @default(false)
  author    User?   @relation(fields: [authorId], references: [id])
  authorId  String?
}

model User {
  id            String       @default(cuid()) @id
  name          String?
  email         String?   @unique
  createdAt     DateTime  @default(now()) @map(name: "created_at")
  updatedAt     DateTime  @updatedAt @map(name: "updated_at")
  posts         Post[]
  @@map(name: "users")
}

Zmienne POSTGRES_PRISMA_URL i POSTGRES_URL_NON_POOLING są nazwami wziętymi z pliku .env ściągniętego z Vercel.

Tworzymy tabele w bazie danych, a właściwie wypychamy schemę do bazy danych:

npx prisma db push

Można sobie sprawdzić w panelu bazy danych na Vercel, czy obie tabele zostały poprawnie utworzone.

Teraz można uruchomić Prisma Studio:

npx prisma studio

Podczas uruchomiania Prisma Studio linia komend wskaże linka z portem, z którego można uruchomić Studio w przeglądarce.

Tworzymy rekordy dla User i Post w Prisma Stidio

Instalujemy Prisma CLient:


npm install @prisma/client

Za każdym razem, gdy plik schema.prisma zostaje zmieniony należy wykonać generowanie:

npx prisma generate

Teraz tworzymy folder lib, a w nim plik prisma.ts

mkdir lib && touch lib/prisma.ts

Wypełniamy plik prisma.ts

// lib/prisma.ts

import { PrismaClient } from '@prisma/client';

let prisma: PrismaClient;

if (process.env.NODE_ENV === 'production') {
  prisma = new PrismaClient();
} else {
  if (!global.prisma) {
    global.prisma = new PrismaClient();
  }
  prisma = global.prisma;
}

export default prisma;

Może być problem z typem dla zmiennej prisma. Wtedy w katalogu głównym projektu utówrz plik global.d.ts

touch global.d.ts

a w nim ten kod:

// /global.d.ts

import { PrismaClient } from '@prisma/client';

declare global {
  // eslint-disable-next-line no-var
  var prisma: PrismaClient;
}

Teraz w każdym miejscu, gdy potrzebujemy dostępu do bazy danych możemy wykorzystać zmienną prisma importując ją tak:

import prisma from '../lib/prisma';

Przykładowe wykorzystanie

W folderze lib tworzymy plik actions.ts

touch lib/actions.ts

Do pliku actions.ts dodajemy funkcję getPosts()

// lib/actions.ts

import prisma from './prisma';

export async function getPosts(isPublished: boolean = true) {
  return prisma.post.findMany({
    where: { published: isPublished },
    include: {
      author: {
        select: { name: true },
      },
    },
  });
}

Tworzymy route posts

mkdir app/posts && touch app/posts/page.tsx

Do pliku posts/page.tsx dodajemy następujący kod, aby zobaczyć nnaniesione wcześniej w Prisma Studio posty:

// posts/page.tsx

import { getPosts } from "@/lib/actions";
import { Post } from "@prisma/client";

export default async function Posts() {
  const posts: Post[] = await getPosts(false);

  return (
    {posts.map((post) => {
      return <div key="{post.id}">{post.title}<div>;
    })}
  );
}

To już prawie wszystko.

Prawie, gdyż w tym stanie deploy na Vercel może pokazać błędy. Jest to spowodawane tym, żę Prisma wymaga uruchomienia npx prism generate po każdej zmianie.

Dodajemy więc "postinstall": "prisma generate" do sekcji "scripts" w pliku package.json

Cała więc sekcja "scripts" powinna wyglądać mniej więcej tak:


"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "postinstall": "prisma generate"
  }

wtorek, 22 października 2024

Jak w Linux znaleźć proces, który działa na porcie 3000


sudo lsof -i :3000

Jeśli chcesz usunąć ten proces, to pobierz PID procesu i

sudo kill -9 PID

sobota, 12 października 2024

Postgres on Docker - podstawowe operacje

Uruchomienie kontenera

docker run -d --name postgresCont -p 5432:5432 -e POSTGRES_PASSWORD=pass123 postgres


Uruchomienie kontenera z wolumenem na lokalnym komputerze (hoście)

docker run -d \
  --name postgresCont \
  -p 5432:5432 \
  -e POSTGRES_PASSWORD=pass123 \
  -v ~/postgres_data:/var/lib/postgresql/data \
  postgres

gdzie ~/postgres_data jest lokalną (na hoście) ścieżką na dane

Sprawdzenie kontenera

docker ps


Wejście do konsoli kontenera

docker exec -it postgresCont bash


Wejście do psql Postgresa
-h - host
-U - użytkownik
-d - baza danych

psql -h localhost -U postgres -d db_name


Jeśli użytkownik nie ma hasła, to można wejść tak:

psql -h localhost -U postgres -d db_name --no-password


Wyświetlenie wszystkich baz danych

\l


Utworzenie bazy danych (średnik na końcu)

CREATE DATABASE test_db;


Podpięcie się do bazy

\c test_db


Utworzenie tabeli

CREATE TABLE tech_authors(ID INT PRIMARY KEY NOT NULL, NAME TEXT NOT NULL, TYPE TEXT NOT NULL, CATEGORY TEXT NOT NULL, ATICLES INT NOT NULL);


Utworzenie rekordu w tabeli

INSERT INTO tech_authors VALUES (1, 'Franio', 'Junior', 'Docker', 3);


Wyświetlenie zawartości tabeli

SELECT * FROM tech_authors;


Usunięcie tabeli

DROP TABLE tech_authors;

W PostgreSQL użytkownik to
ROLE
spore uproszczenie, ale na początek może wystarczyć.
Wyświetlennie użytkowników

\du

Utworzenie użytkownika

CREATE ROLE test_user SUPERUSER;


Zmiana hasła użytkownika

ALTER USER test_user WITH PASSWORD 'MojeHaslo123';


Nadanie użytkownikowi prawa logowania się

ALTER USER test_user WITH LOGIN;


Nadanie użytkownikowi praw

GRANT ALL PRIVILEGES ON DATABASE test_db TO test_user;


Nadanie użytkownikowi prawa własności do bazy

ALTER DATABASE test_db OWNER TO test_user;


Usunięcie użytkownika

DROP ROLE test_user;


Usunięcie bazy danych

DROP DATABASE test_db;


Sprawdzenie ile Docker zajmuje miejsca na dysku (nie tylko sam Postgres) - tylko na MacOS

du -sh ~/Library/Containers/com.docker.docker/


Usunięcie kontenera wraz z wolumenami

docker rm -v postgresCont


Usunięcie nieużywanych wolumenów Dockera

docker volume prune

niedziela, 26 czerwca 2022

Jak wygenerować klusz SSH (prywatny, publiczny)

Rzecz się tyczy systemu Linux.

Generowanie klucza, prosta komenda:


$ ssh-keygen

Jeśli potwierdzisz domyślne, to klucze zostaną umieszczone:

/home/user_name/.ssh/id_rsa
/home/user_name/.ssh/id_rsa.pub

gdzie id_rsa to klucz prywatny, a id_rsa.pub to klucz publiczny.

Dodawanie klucza do agenta ssh aby nie podawać za każdym razem hasła:


$ eval `ssh-agent` 

wyświetli coś w rodzaju Agent pid 9700, więc potem

$ ssh-add ~/.ssh/id_rsa

Teraz w serwisach, które wykorzystują klucze SSH rejestrujesz swój klucz id_rsa.pub i możesz się tam dostać najczęściej bez hasła.

Jeszcze warto by skopiować nowo dodany klucz do terminali, do ktrych się logujesz przez SSH.

Zakładam, że logujes się do maszyny zewnętrznej na przykład tak:


$ ssh user_name@your.external.server.com

wtedy należy tam skopiować id klucz:

$ ssh-copy-id user_name@your.external.server.com

od teraz nie powinien się już pytać o hasło.

poniedziałek, 6 czerwca 2022

Jak wyświetlić zajęte porty

Naprzykład tak:

netstat -antu

A żeby zobaczyć dodatkowo jaka usługa jest uruchumiona na porcie, uruchom jako root z parametrem -p

sudo netstat -antup

Jak "ubić" usługę, która zajmuje port

W tym przypadku na porcie 9001

sudo kill -9 `sudo lsof -t -i:9001`

czwartek, 23 stycznia 2020

SFTP uruchamiane z linii poleceń bez hasła w Linux

Jeśli uruchamiasz SFTP, to klient odpyta się o hasło. Uniemożliwia to skorzystanie z SFTP np. w cron'ie. Da się jednak uruchomić klienta w tzw "batch mode". Wymaga to generowania i przesyłania sobie kluczy ssh. Pełna instrukcja jak to zrobić znajduje się tutaj: https://www.computerhope.com/unix/sftp.htm#Batch-Mode

środa, 22 stycznia 2020

Zmienne w bash'u w Linuxie

Najprostsze użycie zmiennej:

#!/bin/bash          
STR="Hello World!"
echo $STR
Na konsoli na wypisze string "Hello World!".

Tu ciut więcej:

#!/bin/bash          
FILENAME=/var/my-backup-$(date +%Y-%m-%d).tgz
tar -czf $FILENAME /home/me/
Zmienna $FILENAME to string dynamiczny, w skład którego wchodzi data w formacie rok-miesiąc-dzień, np. 20019-12-31. Program tar zarchiwizuje nam w pliku /var/my-backup-2019-12-21.tgz zawartość katalogu /home/me

I jeszcze króciutko o funkcjach i zmiennych lokalnych (local):

#!/bin/bash
HELLO=Hello 
function hello {
    local HELLO=World
    echo $HELLO
}
echo $HELLO
hello
echo $HELLO
Tu zmienna $HELLO przyjmuje najpierw wartość "hello", a po wykonaniu funkcji hello zmienna $HELLO zmienia wartość na "World".

zip i Linux

Kompresowanie plików.

Składnia:

zip [options] zipfile list_of_files_with_spaces

Skompresuj plik filename.txt do archiwum o nazwie myfile.zip:

$ zip myfile filename.txt

Wyciągnij z archiwum:

$ unzip myfile.zip
Uprzednio zarchiwizowany plik filename.txt zostanie wydobyty z archiwum.

Opcja -u czyli aktualizacja pliku w archiwum

$ zip –u filename.zip file.txt
W tym przypadku zostanie zaktualizowany plik file.txt w archiwum filename.zip

Opcja -m czyli usunięcie pliku źródłowego po udanej kompresji archiwum:

$ zip –m filename.zip file.txt
Tu zostanie usunięty plik file.txt

Opcja -r (recursively) czyli archiwizacja całego katalogu:

$ zip –r filename.zip directory_name
Tu zostanie skompresowany folder o nazwie directory_name

cron w Linuxie

Listowanie istniejących zadań crontaba:
$ crontab -l
Edycja zadań crontaba:
$ crontab -e 
Znaczenie poszczególnych gwiazdek w pliku crontaba: Czyli:
  • pierwsza gwiazdka - minuta wykonywania zadania
  • druga gwiazdka - godzina wykonywania zadania
  • trzecia gwiazdka - dzień wykonywania zadania
  • czwarta gwiazdka - jest odpowiednikiem miesiąca od 1 do 12 lub jan - dec (z angielska)
  • no i piąta gwiazdka - jest dniem tygodnia, gdzie 0 i 7 to niedziela! Albo można zapisać z angielska (he he) od sun do sat
Po gwiazdkach następuje komenda systemu Linux lub skrypt. Aby uniknąć niespodzianek należałoby stosować bezwzględne ścieżki dostępu.

Tworzenie zakresów lub częstotliwości:

  • */5 * * * * - wykonaj polecenie co pięć minut każdego dnia
  • 0 13-15 * * * – wykonaj polecenie o 13:00, 14:00 i 15:00 każdego dnia
  • 15 23 * * mon-fri – oznacza zadanie wykonywane codziennie od poniedziałku do piątku o godzinie 23:15
  • 0 4 * * mon-fri/2 – uruchomi polecenie w każdy poniedziałek, środę i piątek o godzinie 4:00

No i w całości:

00 */12 * * * /home/wacek/scripts/rename_files.sh 2>&1
Czyli: co dwanaście godzin (z moich obserwacji o 12:00 i 24:00) wykonaj skrypt z katalogu użytkownika "wacek" i jego katalogu "scripts" plik wykonywalny o nazwie "rename_files.sh"

czwartek, 16 stycznia 2020

Kopiowanie plików poprzez SSH czyli SCP

Oczywiście nie pamiętam składni, a wszystko chcę mieć w jednym miejscu. Po kilku więc szukaniach w necie postanowiłem napisać w swoim miejscu.

Kopiowanie pliku plik.txt z lokalnego hosta na zdalny do katalogu /home/john_doe/other_files:

scp plik.txt john_doe@remote_host.com:other_files

Kopiowanie plików plik1.txt i plik2.txt z lokalnego hosta na zdalny do katalogu /home/john_doe/other_files:

scp plik1.txt plik2.txt john_doe@remote_host.com:other_files

Kopiowanie pliku plik.txt z lokalnego hosta na zdalny do katalogu /home/john_doe/other_files poprzez ssh skonfigurowane na porcie 20021:

scp -P 20021 plik.txt john_doe@remote_host.com:other_files

Kopiowanie pliku /archiw/plik.txt ze zdalnego hosta na lokalny do katalogu /home/other_files:

scp user@remote_host.com:/archiw/plik.txt /home/other_files

Kopiowanie kilku plików ze zdalnego hosta na lokalny do katalogu obecnego:

scp user@remote_host.com:/archiw/{arch1.zip, arch2.zip, arch3.zip} .

środa, 15 stycznia 2020

Utworzenie z konsoli nowego użytkownika Devise w Rails

Niezmiennie zapominam :-)
# Devise
user = User.new(email: 'test@example.com', 
                password: 'password', 
                password_confirmation: 'password')
user.save

Udostępnienie "gołego" pliku przez Google Drive

Dobry skądinąd Google Drive Ma bardzo denerwującą funkcję. Otóż jeśli komuś udostępniasz plik, zwykły plik tekstowy, to osoba otrzymująca link otwiera wcale nie ów plik tekstowy, tylko cały interfejs googlowy. Dopiero w tym interfejsie można sobie plik pobrać. Wkurzające. Szczególnie jeśli chcesz wstawić linki do pobrania na swojej stronie.

Jest jednak na to sposób.

Krótka analiza otrzymanego linka google zaraz po jego udostępnieniu

https://drive.google.com/file/d/1A0PjiDcAt0JUTgScY8hCy56FL6vm-gKJ/view?usp=sharing
W tym linku interesuje nas tylko sam id pliku, a jest nim, w tym przypadku 1A0PjiDcAt0JUTgScY8hCy56FL6vm-gKJ

Wycinamy sobie ten id.

Tutaj jest link do "obierania" interfejsu:

http://drive.google.com/uc?export=view&id=

Wystarczy na końcu dokleić wyekstrahowanyid pliku, co w całości da:

https://drive.google.com/open?id=1A0PjiDcAt0JUTgScY8hCy56FL6vm-gKJ

Ta dam! Mamy "goły" plik.

Całość przeczytałem na https://www.lmeservices.com/share-google-drive-files-via-url/

Wyszukiwanie zawartości w plikach Linux

Zapominam składnię, więc tu sobie składam przykłady.

grep -iRl "your-text-to-find" ./

I przełączniki:

  • -i - ignorowanie wielkości liter
  • -R - szukanie w podkatalogach (recursively search)
  • -l - pokazuj nazwy plików zamiast znalezionych fragmentów tekstów

Parametry:

  • ./ - gdzie ma szukać (w tym przypadku w obecnym katalogu)

Inne przydatne przełączniki:

  • -n - pokazuj numer linii. Wyłącz wtedy opcję -l (tylko nazwy plików) bo nic nie zobaczysz :-)
  • -w - szukaj tylko jako pełny wyraz (whole word only)

I inne przykładowe zapytanie

Wyszukanie ciągu "debugId" we wszystkich plikach z rozszeniem `js` w aktualnym katalogu, w ukrytym podkatalogu `.next`


grep -R 'debugId' ./.next/**/*.js

I wstawka od AI:
**: Jest to wzorzec używany przez bash lub inną powłokę obsługującą “rozszerzenie globbing” (np. w przypadku włączenia opcji globstar w bash lub domyślnie w zsh). Symbolizuje dowolną ilość poziomów katalogów, w tym katalog nadrzędny. W praktyce oznacza: “przeszukaj wszystkie katalogi i ich podkatalogi”.