ํค์ด ํ๋ธ๋ฅด! ๋๋ ๊ธฐ์ฌ์ ๋ฒ์ญ์ ๋น์ ์ ๊ด์ฌ์ ์ ์ํฉ๋๋ค
๋๋ ๊ทธ๊ฒ์ด ๋ชจ์์ด ์๋๋ผ๊ณ ์ฝ์ํ๋ค"
๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ ํจ๋ฌ๋ค์๊ณผ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ํจ๋ฌ๋ค์์ ์๋ก ์์ถฉ๋๋ ๊ฒ์ฒ๋ผ ๋ณด์ผ ์ ์์ง๋ง ๋ ๋ค Powershell์์ ๋์ผํ๊ฒ ์ง์๋ฉ๋๋ค. ๊ธฐ๋ฅ์ ์ด๋ ์๋๋ ๊ฑฐ์ ๋ชจ๋ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์๋ ํ์ฅ๋ ์ด๋ฆ-๊ฐ ๋ฐ์ธ๋ฉ ๊ธฐ๋ฅ์ด ์์ต๋๋ค. ๊ตฌ์กฐ์ฒด ๋ฐ ๋ ์ฝ๋์ ๊ฐ์ ํด๋์ค๋ ํ๋์ ์ ๊ทผ ๋ฐฉ์์ผ ๋ฟ์ ๋๋ค. ํด๋์ค ์ฌ์ฉ์ ์ด๋ฆ๊ณผ ๊ฐ ๋ฐ์ธ๋ฉ์ผ๋ก ์ ํํ๊ณ ์์, ๋คํ์ฑ ๋๋ ๊ฐ๋ณ์ฑ๊ณผ ๊ฐ์ ๋ฌด๊ฑฐ์ด ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ ๊ฐ๋ ์ ํผํ๋ค๋ฉด ์ฝ๋๋ฅผ ๋ณต์กํ๊ฒ ํ์ง ์๊ณ ๋ ํด๋์ค์ ์ด์ ์ ํ์ฉํ ์ ์์ต๋๋ค. ๋ํ ๋ถ๋ณ ์ ํ ๋ณํ ๋ฐฉ๋ฒ์ ์ถ๊ฐํ๋ฉด ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ๊ธฐ๋ฅ ์ฝ๋๋ฅผ ํ๋ถํ๊ฒ ํ ์ ์์ต๋๋ค.
์นด์คํธ์ ๋ง๋ฒ
์นด์คํธ๋ Powershell์ ๊ฐ์ฅ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ ์ค ํ๋์ ๋๋ค. ๊ฐ์ ์บ์คํ ํ ๋ ํ๊ฒฝ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ถ๊ฐํ๋ ์์์ ์ด๊ธฐํ ๋ฐ ์ ํจ์ฑ ๊ฒ์ฌ ๊ธฐ๋ฅ์ ์์กดํ๊ฒ ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด, [xml]์์ ๋ฌธ์์ด์ ์บ์คํ ํ๋ฉด ํ์ ์ฝ๋๋ฅผ ํตํด ๋ฌธ์์ด์ด ์คํ๋๊ณ ์์ ํ xml ํธ๋ฆฌ๊ฐ ์์ฑ๋ฉ๋๋ค. ๋์ผํ ๋ชฉ์ ์ผ๋ก ์ฝ๋์์ ํด๋์ค๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์บ์คํธ ํด์ํ ์ด๋ธ
์์ฑ์๊ฐ ์์ผ๋ฉด ํด์ํ ์ด๋ธ์ ํด๋์ค ์ ํ์ผ๋ก ์บ์คํ ํ์ฌ ์์ฑ์ ์์ด ๊ณ์ํ ์ ์์ต๋๋ค. ์ด ํจํด์ ์ต๋ํ ํ์ฉํ๋ ค๋ฉด ์ ํจ์ฑ ๊ฒ์ฌ ์์ฑ์ ์ฌ์ฉํ๋ ๊ฒ์ ์์ง ๋ง์ธ์. ๋์์ ํด๋์ค์ ํ์ํ๋ ์์ฑ์ ์ฌ์ฉํ์ฌ ํจ์ฌ ๋ ์ฌ์ธต์ ์ธ ์ด๊ธฐํ ๋ฐ ์ ํจ์ฑ ๊ฒ์ฌ ๋ ผ๋ฆฌ๋ฅผ ์คํํ ์ ์์ต๋๋ค.
class Cluster {
[ValidatePattern("^[A-z]+$")]
[string] $Service
[ValidateSet("TEST", "STAGE", "CANARY", "PROD")]
[string] $FlightingRing
[ValidateSet("EastUS", "WestUS", "NorthEurope")]
[string] $Region
[ValidateRange(0, 255)]
[int] $Index
}
[Cluster]@{
Service = "MyService"
FlightingRing = "PROD"
Region = "EastUS"
Index = 2
}
๋ํ ์บ์คํ ์ ๊น๋ํ ์ถ๋ ฅ์ ์ป๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค. Format-Table์ ์ ๋ฌ๋ ํด๋ฌ์คํฐ ํด์ํ ์ด๋ธ ๋ฐฐ์ด์ ์ถ๋ ฅ์ ์ด๋ฌํ ํด์ํ ์ด๋ธ์ ํด๋์ค์ ์ฒ์ ์บ์คํ ํ ๋ ์ป๋ ๊ฒฐ๊ณผ์ ๋น๊ตํ์ธ์. ํด๋์ค์ ์์ฑ์ ํญ์ ์ ์๋ ์์๋๋ก ๋์ด๋ฉ๋๋ค. ๊ฒฐ๊ณผ์ ํ์ํ๊ณ ์ถ์ง ์์ ๋ชจ๋ ์์ฑ ์์ ์จ๊ฒจ์ง ํค์๋๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ์์ง ๋ง์ธ์.
์๋ฏธ์ ์บ์คํ
์ธ์๊ฐ ํ๋์ธ ์์ฑ์๊ฐ ์๋ ๊ฒฝ์ฐ ํด๋์ค ์ ํ์ ๊ฐ์ ์บ์คํ ํ๋ฉด ํด๋น ๊ฐ์ด ์์ฑ์์ ์ ๋ฌ๋์ด ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ์ด๊ธฐํํ ์ ์์ต๋๋ค.
class Cluster {
[ValidatePattern("^[A-z]+$")]
[string] $Service
[ValidateSet("TEST", "STAGE", "CANARY", "PROD")]
[string] $FlightingRing
[ValidateSet("EastUS", "WestUS", "NorthEurope")]
[string] $Region
[ValidateRange(0, 255)]
[int] $Index
Cluster([string] $id) {
$this.Service, $this.FlightingRing, $this.Region, $this.Index = $id -split "-"
}
}
[Cluster]"MyService-PROD-EastUS-2"
๋ผ์ธ์ ์บ์คํธ
[string] ToString() ํด๋์ค ๋ฉ์๋๋ฅผ ์ฌ์ ์ํ์ฌ ๋ฌธ์์ด ๋ณด๊ฐ ์ฌ์ฉ๊ณผ ๊ฐ์ ๊ฐ์ฒด์ ๋ฌธ์์ด ํํ ๋ค์ ์๋ ๋ ผ๋ฆฌ๋ฅผ ์ ์ํ ์๋ ์์ต๋๋ค.
class Cluster {
[ValidatePattern("^[A-z]+$")]
[string] $Service
[ValidateSet("TEST", "STAGE", "CANARY", "PROD")]
[string] $FlightingRing
[ValidateSet("EastUS", "WestUS", "NorthEurope")]
[string] $Region
[ValidateRange(0, 255)]
[int] $Index
[string] ToString() {
return $this.Service, $this.FlightingRing, $this.Region, $this.Index -join "-"
}
}
$cluster = [Cluster]@{
Service = "MyService"
FlightingRing = "PROD"
Region = "EastUS"
Index = 2
}
Write-Host "We just created a model for '$cluster'"
์ง๋ ฌํ๋ ์ธ์คํด์ค ์ ์ก
Cast๋ ์์ ํ ์ญ์ง๋ ฌํ๋ฅผ ํ์ฉํฉ๋๋ค. ๋ฐ์ดํฐ๊ฐ ํด๋ฌ์คํฐ์ ์ฌ์์ ์ถฉ์กฑํ์ง ์์ผ๋ฉด ์๋ ์๋ ์คํจํฉ๋๋ค.
# ะะฐะปะธะดะฐัะธั ัะตัะธะฐะปะธะทะพะฒะฐะฝะฝัั
ะดะฐะฝะฝัั
[Cluster]$cluster = Get-Content "./my-cluster.json" | ConvertFrom-Json
[Cluster[]]$clusters = Import-Csv "./my-clusters.csv"
๊ธฐ๋ฅ ์ฝ๋์ ์บ์คํธ
๊ธฐ๋ฅ์ ํ๋ก๊ทธ๋จ์ ๋จผ์ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ ์ํ ๋ค์ ๋ถ๋ณ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ๋ํ ์ผ๋ จ์ ๋ณํ์ผ๋ก ํ๋ก๊ทธ๋จ์ ๊ตฌํํฉ๋๋ค. ๋ชจ์๋ ์ธ์์๋ ๋ถ๊ตฌํ๊ณ ํด๋์ค๋ ์ ํ ๋ณํ ๋ฐฉ๋ฒ ๋๋ถ์ ๊ธฐ๋ฅ์ ์ฝ๋๋ฅผ ์์ฑํ๋ ๋ฐ ์ค์ ๋ก ๋์์ด ๋ฉ๋๋ค.
๋ด๊ฐ ์์ฑ ์ค์ธ Powershell์ด โโ์๋ํ๋์?
C# ๋๋ ์ด์ ์ ์ฌํ ๋ฐฐ๊ฒฝ์ ๊ฐ์ง ๋ง์ ์ฌ๋๋ค์ด C#๊ณผ ์ ์ฌํ Powershell์ ์์ฑํ๊ณ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ๊ฐ๋ ์ ์ฌ์ฉํ๋ ๊ฒ์์ ๋ฒ์ด๋ Powershell์ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ์ง์คํ๊ฑฐ๋ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ๋ํด ๋ ๋ง์ด ๋ฐฐ์ฐ๋ ๊ฒ์ด ๋์์ด ๋ ๊ฒ์ ๋๋ค.
ํ์ดํ๋ผ์ธ(|), Where-Object, ForEach-Object, Select-Object, Group-Object, Sort-Object ๋ฑ์ ์ฌ์ฉํ์ฌ ๋ถ๋ณ ๋ฐ์ดํฐ ๋ณํ์ ํฌ๊ฒ ์์กดํ๋ ๊ฒฝ์ฐ ๋ ๊ธฐ๋ฅ์ ์ธ ์คํ์ผ์ ๊ฐ๊ฒ ๋๋ฉฐ Powershell์ ์ฌ์ฉํ๋ฉด ์ด์ ์ ์ป์ ์ ์์ต๋๋ค. ๊ธฐ๋ฅ์ ์คํ์ผ์ ์์ .
ํด๋์ค์ ๊ธฐ๋ฅ์ ์ฌ์ฉ
์นด์คํธ๋ ๋์ฒด ๊ตฌ๋ฌธ์ ์ฌ์ฉํ์ง๋ง ๋จ์ง ๋ ์์ญ ๊ฐ์ ๋งคํ์ผ ๋ฟ์ ๋๋ค. ํ์ดํ๋ผ์ธ์์ ForEach-Object๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ๋ฐฐ์ด์ ๋งคํํ ์ ์์ต๋๋ค.
์๋ ์์์๋ Datum์ด ์บ์คํ ๋ ๋๋ง๋ค Node ์์ฑ์๊ฐ ์คํ๋๋ฏ๋ก ์๋นํ ์์ ์ฝ๋ ์์ฑ์ ํผํ ์ ์์ต๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ์ฐ๋ฆฌ ํ์ดํ๋ผ์ธ์ ์ ์ธ์ ๋ฐ์ดํฐ ์ฟผ๋ฆฌ ๋ฐ ์ง๊ณ์ ์ค์ ์ ๋๊ณ ํด๋์ค๋ ๋ฐ์ดํฐ ๊ตฌ๋ฌธ ๋ถ์ ๋ฐ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ๋ด๋นํฉ๋๋ค.
# ะัะธะผะตั ะบะพะผะฑะธะฝะธัะพะฒะฐะฝะธั ะบะปะฐััะพะฒ ั ะบะพะฝะฒะตะนะตัะฐะผะธ ะดะปั separation of concerns ะฒ ะบะพะฝะฒะตะนะตัะฐั
class Node {
[ValidateLength(3, 7)]
[string] $Name
[ValidateSet("INT", "PPE", "PROD")]
[string] $FlightingRing
[ValidateSet("EastUS", "WestUS", "NorthEurope", "WestEurope")]
[string] $Region
Node([string] $Name) {
$Name -match "([a-z]+)(INT|PPE|PROD)([a-z]+)"
$_, $this.Service, $this.FlightingRing, $this.Region = $Matches
$this.Name = $Name
}
}
class Datum {
[string] $Name
[int] $Value
[Node] $Computer
[int] Severity() {
$this.Name -match "[0-9]+$"
return $Matches[0]
}
}
Write-Host "Urgent Security Audit Issues:"
Import-Csv "./audit-results.csv" `
| ForEach-Object {[Datum]$_} `
| Where-Object Value -gt 0 `
| Group-Object {$_.Severity()} `
| Where-Object Name -lt 2 `
| ForEach-Object Group `
| ForEach-Object Computer `
| Where-Object FlightingRing -eq "PROD" `
| Sort-Object Name, Region -Unique
์ฌ์ฌ์ฉ์ ์ํ ํฌ์ฅ ํด๋์ค
๋ณด์ด๋ ๊ฒ๋งํผ ์ข์ ๊ฒ์ ์์ต๋๋ค
์ํ๊น๊ฒ๋ ํด๋์ค๋ ํจ์๋ ๋ณ์์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋ชจ๋์์ ๋ด๋ณด๋ผ ์ ์์ต๋๋ค. ํ์ง๋ง ๋ช ๊ฐ์ง ํธ๋ฆญ์ด ์์ต๋๋ค. ํด๋์ค๊ฐ ./my-classes.ps1 ํ์ผ์ ์ ์๋์ด ์๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค.
-
ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ํ์ผ์ ๋ํธ์์ฑํ ์ ์์ต๋๋ค. ./my-classes.ps1. ๊ทธ๋ฌ๋ฉด ํ์ฌ ๋ฒ์์์ my-classes.ps1์ด ์คํ๋๊ณ ํด๋น ํ์ผ์ ๋ชจ๋ ํด๋์ค๊ฐ ์ ์๋ฉ๋๋ค.
-
๋ชจ๋ ์ฌ์ฉ์ ์ง์ API(cmdlet)๋ฅผ ๋ด๋ณด๋ด๋ Powershell ๋ชจ๋์ ๋ง๋ค๊ณ ๋ชจ๋ ๋งค๋ํ์คํธ์์ ScriptsToProcess = "./my-classes.ps1" ๋ณ์๋ฅผ ์ค์ ํ๋ฉด ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค. ./my-classes.ps1์ ๋ค์์์ ์คํ๋ฉ๋๋ค. ๋น์ ์ ํ๊ฒฝ.
์ด๋ค ์ต์
์ ์ ํํ๋ Powershell์ ์ ํ ์์คํ
์ ๋ค๋ฅธ ์์น์์ ๋ก๋๋ ๋์ผํ ์ด๋ฆ์ ์ ํ์ ํ์ธํ ์ ์์ต๋๋ค.
์๋ก ๋ค๋ฅธ ์์น์์ ๋์ผํ ์์ฑ์ ๊ฐ์ง ๋ ๊ฐ์ ๋์ผํ ํด๋์ค๋ฅผ ๋ก๋ํ ๊ฒฝ์ฐ์๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ํ์ด ์์ต๋๋ค.
์์ผ๋ก์ ๊ธธ
์ ํ ํ์ธ ๋ฌธ์ ๋ฅผ ํผํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ํด๋์ค๋ฅผ ์ฌ์ฉ์์๊ฒ ๋ ธ์ถํ์ง ์๋ ๊ฒ์ ๋๋ค. ์ฌ์ฉ์๊ฐ ํด๋์ค ์ ์ ์ ํ์ ๊ฐ์ ธ์ฌ ๊ฒ์ผ๋ก ๊ธฐ๋ํ๋ ๋์ , ํด๋์ค์ ์ง์ ์ก์ธ์คํ ํ์๊ฐ ์๋ ํจ์๋ฅผ ๋ชจ๋์์ ๋ด๋ณด๋ด์ญ์์ค. ํด๋ฌ์คํฐ์ ๊ฒฝ์ฐ ์ฌ์ฉ์ ์นํ์ ์ธ ๋งค๊ฐ๋ณ์ ์ธํธ๋ฅผ ์ง์ํ๊ณ ํด๋ฌ์คํฐ๋ฅผ ๋ฐํํ๋ New-Cluster ํจ์๋ฅผ ๋ด๋ณด๋ผ ์ ์์ต๋๋ค.
class Cluster {
[ValidatePattern("^[A-z]+$")]
[string] $Service
[ValidateSet("TEST", "STAGE", "CANARY", "PROD")]
[string] $FlightingRing
[ValidateSet("EastUS", "WestUS", "NorthEurope")]
[string] $Region
[ValidateRange(0, 255)]
[int] $Index
}
function New-Cluster {
[OutputType([Cluster])]
Param(
[Parameter(Mandatory, ParameterSetName = "Id", Position = 0)]
[ValidateNotNullOrEmpty()]
[string] $Id,
[Parameter(Mandatory, ParameterSetName = "Components")]
[string] $Service,
[Parameter(Mandatory, ParameterSetName = "Components")]
[string] $FlightingRing,
[Parameter(Mandatory, ParameterSetName = "Components")]
[string] $Region,
[Parameter(Mandatory, ParameterSetName = "Components")]
[int] $Index
)
if ($Id) {
$Service, $FlightingRing, $Region, $Index = $Id -split "-"
}
[Cluster]@{
Service = $Service
FlightingRing = $FlightingRing
Region = $Region
Index = $Index
}
}
Export-ModuleMember New-Cluster
๋ ๋ฌด์์ ์ฝ์๊น
์ถ์ฒ : habr.com