mirror of
https://github.com/foomo/posh-providers.git
synced 2025-10-16 12:35:41 +00:00
Merge branch 'main' into main
This commit is contained in:
commit
4c13fb8534
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@ -16,13 +16,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
- uses: sourcemeta/jsonschema@v9.3.5
|
||||
- uses: sourcemeta/jsonschema@v11.1.1
|
||||
|
||||
#- uses: gotesttools/gotestfmt-action@v2
|
||||
# with:
|
||||
|
||||
@ -2,6 +2,8 @@ package az
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/foomo/posh/pkg/log"
|
||||
@ -11,11 +13,21 @@ import (
|
||||
|
||||
func AuthChecker(ctx context.Context, l log.Logger) []check.Info {
|
||||
name := "Azure"
|
||||
out, err := shell.New(ctx, l, "az", "account", "list", "--output", "none").Quiet().CombinedOutput()
|
||||
out, err := shell.New(ctx, l, "az", "account", "list", "--output", "json").Quiet().CombinedOutput()
|
||||
if err != nil {
|
||||
return []check.Info{check.NewFailureInfo(name, "Error: "+err.Error())}
|
||||
} else if strings.Contains(string(out), "az login") {
|
||||
return []check.Info{check.NewNoteInfo(name, "Unauthenticated")}
|
||||
}
|
||||
return []check.Info{check.NewSuccessInfo(name, "Authenticated")}
|
||||
|
||||
var res []map[string]any
|
||||
note := "Authenticated"
|
||||
if err := json.Unmarshal(out, &res); err == nil {
|
||||
if len(res) > 0 && res[0]["user"] != nil {
|
||||
if user, ok := res[0]["user"].(map[string]any); ok {
|
||||
note += fmt.Sprintf(" as %s: %s", user["type"], user["name"])
|
||||
}
|
||||
}
|
||||
}
|
||||
return []check.Info{check.NewSuccessInfo(name, note)}
|
||||
}
|
||||
|
||||
@ -69,7 +69,14 @@ func NewCommand(l log.Logger, az *AZ, kubectl *kubectl.Kubectl, opts ...CommandO
|
||||
{
|
||||
Name: "login",
|
||||
Description: "Log in to Azure",
|
||||
Execute: inst.login,
|
||||
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
|
||||
fs.Internal().String("service-principal", "", "Service principal to use for authentication")
|
||||
if err := fs.Internal().SetValues("service-principal", inst.az.Config().ServicePrincipalNames()...); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Execute: inst.login,
|
||||
},
|
||||
{
|
||||
Name: "logout",
|
||||
@ -240,10 +247,34 @@ func (c *Command) exec(ctx context.Context, r *readline.Readline) error {
|
||||
|
||||
func (c *Command) login(ctx context.Context, r *readline.Readline) error {
|
||||
fs := r.FlagSets().Default()
|
||||
return shell.New(ctx, c.l, "az", "login",
|
||||
"--allow-no-subscriptions",
|
||||
"--tenant", c.az.Config().TenantID,
|
||||
).
|
||||
ifs := r.FlagSets().Internal()
|
||||
|
||||
servicePricipal, err := ifs.GetString("service-principal")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var args []string
|
||||
if servicePricipal != "" {
|
||||
sp, err := c.az.cfg.ServicePrincipal(servicePricipal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
args = append(args,
|
||||
"--service-principal",
|
||||
"--username", sp.ClientID,
|
||||
"--password", sp.ClientSecret,
|
||||
"--tenant", sp.TenantID,
|
||||
)
|
||||
} else {
|
||||
args = append(args,
|
||||
"--allow-no-subscriptions",
|
||||
"--tenant", c.az.Config().TenantID,
|
||||
)
|
||||
}
|
||||
|
||||
return shell.New(ctx, c.l, "az", "login").
|
||||
Args(args...).
|
||||
Args(fs.Visited().Args()...).
|
||||
Args(r.AdditionalArgs()...).
|
||||
Args(r.AdditionalFlags()...).
|
||||
|
||||
@ -14,6 +14,17 @@ type Config struct {
|
||||
TenantID string `json:"tenantId" yaml:"tenantId"`
|
||||
// Subscription configurations
|
||||
Subscriptions map[string]Subscription `json:"subscriptions" yaml:"subscriptions"`
|
||||
// Authentication service principals
|
||||
ServicePrincipals map[string]ServicePrincipal `json:"servicePrincipals" yaml:"servicePrincipals"`
|
||||
}
|
||||
|
||||
type ServicePrincipal struct {
|
||||
// Tenant id
|
||||
TenantID string `json:"tenantId" yaml:"tenantId"`
|
||||
// Application client id
|
||||
ClientID string `json:"clientId" yaml:"clientId"`
|
||||
// Application password
|
||||
ClientSecret string `json:"clientSecret" yaml:"clientSecret"`
|
||||
}
|
||||
|
||||
func (c Config) Subscription(name string) (Subscription, error) {
|
||||
@ -29,3 +40,17 @@ func (c Config) SubscriptionNames() []string {
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
func (c Config) ServicePrincipal(name string) (ServicePrincipal, error) {
|
||||
value, ok := c.ServicePrincipals[name]
|
||||
if !ok {
|
||||
return ServicePrincipal{}, errors.Errorf("service principal not found: %s", name)
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (c Config) ServicePrincipalNames() []string {
|
||||
keys := lo.Keys(c.ServicePrincipals)
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
@ -53,6 +53,13 @@
|
||||
},
|
||||
"type": "object",
|
||||
"description": "Subscription configurations"
|
||||
},
|
||||
"servicePrincipals": {
|
||||
"additionalProperties": {
|
||||
"$ref": "#/$defs/ServicePrincipal"
|
||||
},
|
||||
"type": "object",
|
||||
"description": "Authentication service principals"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -60,7 +67,31 @@
|
||||
"required": [
|
||||
"configPath",
|
||||
"tenantId",
|
||||
"subscriptions"
|
||||
"subscriptions",
|
||||
"servicePrincipals"
|
||||
]
|
||||
},
|
||||
"ServicePrincipal": {
|
||||
"properties": {
|
||||
"tenantId": {
|
||||
"type": "string",
|
||||
"description": "Tenant id"
|
||||
},
|
||||
"clientId": {
|
||||
"type": "string",
|
||||
"description": "Application client id"
|
||||
},
|
||||
"clientSecret": {
|
||||
"type": "string",
|
||||
"description": "Application password"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"required": [
|
||||
"tenantId",
|
||||
"clientId",
|
||||
"clientSecret"
|
||||
]
|
||||
},
|
||||
"Subscription": {
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
# yaml-language-server: $schema=config.schema.json
|
||||
configPath: .posh/config/azure
|
||||
tenantId: xxxx-xx-xx-xx-xxxx
|
||||
servicePrincipals:
|
||||
dev:
|
||||
tenantId: xxxx-xx-xx-xx-xxxx
|
||||
clientId: xxxx-xx-xx-xx-xxxx
|
||||
clientSecret: xxxx-xx-xx-xx-xxxx
|
||||
subscriptions:
|
||||
development:
|
||||
name: xxxx-xx-xx-xx-xxxx
|
||||
|
||||
2
go.mod
2
go.mod
@ -11,7 +11,7 @@ require (
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
|
||||
github.com/c-bata/go-prompt v0.2.6
|
||||
github.com/cloudrecipes/packagejson v1.0.0
|
||||
github.com/digitalocean/godo v1.161.0
|
||||
github.com/digitalocean/godo v1.162.0
|
||||
github.com/foomo/go v0.0.3
|
||||
github.com/foomo/gokazi v0.1.5
|
||||
github.com/foomo/posh v0.13.0
|
||||
|
||||
4
go.sum
4
go.sum
@ -39,8 +39,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/digitalocean/godo v1.161.0 h1:Q/3ImcotZp0GV9FY/dnLj9TmfOd+a7ZN/UNuhgDHI/Q=
|
||||
github.com/digitalocean/godo v1.161.0/go.mod h1:tYeiWY5ZXVpU48YaFv0M5irUFHXGorZpDNm7zzdWMzM=
|
||||
github.com/digitalocean/godo v1.162.0 h1:7dtS9H8xsUuYtPf9w4eDsiRl0UlgzyCCSPWpMFOZKhg=
|
||||
github.com/digitalocean/godo v1.162.0/go.mod h1:NJ1VlXmFMSnG1GEe2rWyDZVrhR69c3nHmL0s1cSSQ6M=
|
||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
|
||||
@ -104,7 +104,7 @@ func NewCommand(l log.Logger, az *az.AZ, op *onepassword.OnePassword, cache cach
|
||||
return nil
|
||||
},
|
||||
Execute: func(ctx context.Context, r *readline.Readline) error {
|
||||
be, err := inst.cfg.Backend(r.Args().At(0))
|
||||
backend, err := inst.cfg.Backend(r.Args().At(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -123,11 +123,11 @@ func NewCommand(l log.Logger, az *az.AZ, op *onepassword.OnePassword, cache cach
|
||||
storageArgs = strings.Trim(strings.Trim(storageArgs, "\""), "'")
|
||||
|
||||
// Create a new resource group
|
||||
inst.l.Info("creating resource group:", be.ResourceGroup)
|
||||
inst.l.Info("creating resource group:", backend.ResourceGroup)
|
||||
if err := shell.New(ctx, inst.l, "az", "group", "create").
|
||||
Args("--resource-group", be.ResourceGroup).
|
||||
Args("--subscription", be.Subscription).
|
||||
Args("--location", be.Location).
|
||||
Args("--resource-group", backend.ResourceGroup).
|
||||
Args("--subscription", backend.Subscription).
|
||||
Args("--location", backend.Location).
|
||||
Args(strings.Split(groupArgs, " ")...).
|
||||
Args(r.FlagSets().Default().Visited().Args()...).
|
||||
Run(); err != nil {
|
||||
@ -135,12 +135,12 @@ func NewCommand(l log.Logger, az *az.AZ, op *onepassword.OnePassword, cache cach
|
||||
}
|
||||
|
||||
// Create a new resource group
|
||||
inst.l.Info("creating storage account:", be.StorageAccount)
|
||||
inst.l.Info("creating storage account:", backend.StorageAccount)
|
||||
if err := shell.New(ctx, inst.l, "az", "storage", "account", "create").
|
||||
Args("--name", be.StorageAccount).
|
||||
Args("--resource-group", be.ResourceGroup).
|
||||
Args("--subscription", be.Subscription).
|
||||
Args("--location", be.Location).
|
||||
Args("--name", backend.StorageAccount).
|
||||
Args("--resource-group", backend.ResourceGroup).
|
||||
Args("--subscription", backend.Subscription).
|
||||
Args("--location", backend.Location).
|
||||
Args(strings.Split(storageArgs, " ")...).
|
||||
Args(r.FlagSets().Default().Visited().Args()...).
|
||||
Run(); err != nil {
|
||||
@ -148,23 +148,16 @@ func NewCommand(l log.Logger, az *az.AZ, op *onepassword.OnePassword, cache cach
|
||||
}
|
||||
|
||||
// retrieve storage key
|
||||
inst.l.Info("retrieving storage key")
|
||||
sk, err := shell.New(ctx, inst.l, "az", "storage", "account", "keys", "list").
|
||||
Args("--resource-group", be.ResourceGroup).
|
||||
Args("--subscription", be.Subscription).
|
||||
Args("--account-name", be.StorageAccount).
|
||||
Args("-o", "tsv", "--query", "'[0].value'").
|
||||
Output()
|
||||
storageAccountKey, err := inst.getStorageAccountKey(ctx, backend)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sks := strings.ReplaceAll(strings.TrimSpace(string(sk)), "\n", "")
|
||||
|
||||
inst.l.Info("creating storage container:", be.Container)
|
||||
inst.l.Info("creating storage container:", backend.Container)
|
||||
return shell.New(ctx, inst.l, "az", "storage", "container", "create").
|
||||
Args("--account-name", be.StorageAccount).
|
||||
Args("--account-key", sks).
|
||||
Args("--name", be.Container).
|
||||
Args("--account-name", backend.StorageAccount).
|
||||
Args("--account-key", storageAccountKey).
|
||||
Args("--name", backend.Container).
|
||||
Run()
|
||||
},
|
||||
},
|
||||
@ -172,15 +165,21 @@ func NewCommand(l log.Logger, az *az.AZ, op *onepassword.OnePassword, cache cach
|
||||
Name: "login",
|
||||
Description: "Log into your object storage backend",
|
||||
Execute: func(ctx context.Context, r *readline.Readline) error {
|
||||
be, sks, err := inst.backendKey(ctx, r.Args().At(0))
|
||||
backend, err := inst.cfg.Backend(r.Args().At(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return shell.New(ctx, inst.l, "pulumi", "login", fmt.Sprintf("azblob://%s", be.Container)).
|
||||
Env("AZURE_STORAGE_ACCOUNT=" + be.StorageAccount).
|
||||
Env("AZURE_STORAGE_KEY=" + sks).
|
||||
Env("ARM_SUBSCRIPTION_ID=" + be.Subscription).
|
||||
storageAccountKey, err := inst.getStorageAccountKey(ctx, backend)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return shell.New(ctx, inst.l, "pulumi", "login", fmt.Sprintf("azblob://%s", backend.Container)).
|
||||
Env("AZURE_STORAGE_ACCOUNT=" + backend.StorageAccount).
|
||||
Env("AZURE_STORAGE_KEY=" + storageAccountKey).
|
||||
Env("ARM_SUBSCRIPTION_ID=" + backend.Subscription).
|
||||
Debug().
|
||||
Run()
|
||||
},
|
||||
},
|
||||
@ -503,7 +502,12 @@ func (c *Command) executeStack(ctx context.Context, r *readline.Readline) error
|
||||
proj := r.Args().At(2)
|
||||
stack := r.Args().At(3)
|
||||
|
||||
be, storageAccountKey, err := c.backendKey(ctx, e)
|
||||
be, err := c.cfg.Backend(r.Args().At(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
storageAccountKey, err := c.getStorageAccountKey(ctx, be)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -551,12 +555,7 @@ func (c *Command) completeProjects(ctx context.Context, t tree.Root, r *readline
|
||||
}).([]goprompt.Suggest)
|
||||
}
|
||||
|
||||
func (c *Command) backendKey(ctx context.Context, env string) (Backend, string, error) {
|
||||
be, err := c.cfg.Backend(env)
|
||||
if err != nil {
|
||||
return Backend{}, "", err
|
||||
}
|
||||
|
||||
func (c *Command) getStorageAccountKey(ctx context.Context, be Backend) (string, error) {
|
||||
// retrieve storage key
|
||||
c.l.Info("retrieving storage key")
|
||||
sk, err := shell.New(ctx, c.l, "az", "storage", "account", "keys", "list").
|
||||
@ -566,10 +565,10 @@ func (c *Command) backendKey(ctx context.Context, env string) (Backend, string,
|
||||
Args("-o", "tsv", "--query", "'[0].value'").
|
||||
Output()
|
||||
if err != nil {
|
||||
return Backend{}, "", err
|
||||
return "", err
|
||||
}
|
||||
|
||||
return be, strings.ReplaceAll(strings.TrimSpace(string(sk)), "\n", ""), nil
|
||||
return strings.ReplaceAll(strings.TrimSpace(string(sk)), "\n", ""), nil
|
||||
}
|
||||
|
||||
func (c *Command) completeStacks(ctx context.Context, t tree.Root, r *readline.Readline) []goprompt.Suggest {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user