Merge pull request #205 from foomo/azure-az-tenant-id

feat(azure/az) feat: tenant id
This commit is contained in:
Kevin Franklin Kim 2025-04-28 11:10:51 +02:00 committed by GitHub
commit 04982c5767
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 93 additions and 64 deletions

View File

@ -7,72 +7,54 @@ This provider requires `az` to be installed on your system.
### Plugin
```go
package main
type Plugin struct {
l log.Logger
az *az.AZ
cache cache.Cache
kubectl *kubectl.Kubectl
commands command.Commands
}
func New(l log.Logger) (plugin.Plugin, error) {
var err error
inst := &Plugin{
l: l,
cache: &cache.MemoryCache{},
commands: command.Commands{},
}
// ...
inst.kubectl, err = kubectl.New(l, inst.cache)
if err != nil {
return nil, errors.Wrap(err, "failed to create kubectl")
}
inst.az, err = az.New(l, inst.cache)
if err != nil {
return nil, errors.Wrap(err, "failed to create az")
}
// ...
inst.commands.Add(az.NewCommand(l, inst.az, inst.kubectl))
// ...
return inst, nil
}
inst.commands.Add(az.NewCommand(l, inst.az, inst.kubectl))
```
### Config
```yaml
## az
az:
configPath: .posh/config/azure
tenantId: xxxx-xx-xx-xx-xxxx
subscriptions:
production:
name: my-subscription
development:
name: xxxx-xx-xx-xx-xxxx
clusters:
default:
name: aks-my-prod
dev:
name: my-cluster
resourceGroup: my-resource-group
artifactories:
default:
name: acr-my-prod
dev:
name: my-artifactory
resourceGroup: my-resource-group
```
### Ownbrew
### Commands
To install binary locally, add:
```shell
> help az
Manage azure resources
```yaml
ownbrew:
packages:
## https://github.com/Azure/kubelogin/releases
- name: kubelogin
tap: foomo/tap/azure/kubelogin
version: 0.1.0
Usage:
az [command]
Available Commands:
login Log in to Azure
logout Log out to remove access to Azure subscriptions
configure Manage Azure CLI configuration
artifactory Login into the artifactory
kubeconfig Retrieve credentials to access remote cluster
```
#### Examples
```shell
# Log into azure tenant
> az login
# Authorize artifactory
> az artifactory <SUBSCRIPTION> <ARTIFACTORY>
# Retrieve cluster kubeconfig
> az kubeconfig <SUBSCRIPTION> <CLUSTER>
```

21
azure/az/checker.go Normal file
View File

@ -0,0 +1,21 @@
package az
import (
"context"
"strings"
"github.com/foomo/posh/pkg/log"
"github.com/foomo/posh/pkg/prompt/check"
"github.com/foomo/posh/pkg/shell"
)
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()
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")}
}

View File

@ -69,11 +69,7 @@ func NewCommand(l log.Logger, az *AZ, kubectl *kubectl.Kubectl, opts ...CommandO
{
Name: "login",
Description: "Log in to Azure",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
fs.Default().String("tenant", "", "The Microsoft Entra tenant")
return nil
},
Execute: inst.exec,
Execute: inst.login,
},
{
Name: "logout",
@ -241,3 +237,15 @@ func (c *Command) exec(ctx context.Context, r *readline.Readline) error {
Args(r.AdditionalFlags()...).
Run()
}
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,
).
Args(fs.Visited().Args()...).
Args(r.AdditionalArgs()...).
Args(r.AdditionalFlags()...).
Run()
}

View File

@ -10,6 +10,8 @@ import (
type Config struct {
// Config path
ConfigPath string `json:"configPath" yaml:"configPath"`
// Tenant id
TenantID string `json:"tenantId" yaml:"tenantId"`
// Subscription configurations
Subscriptions map[string]Subscription `json:"subscriptions" yaml:"subscriptions"`
}

View File

@ -43,6 +43,10 @@
"type": "string",
"description": "Config path"
},
"tenantId": {
"type": "string",
"description": "Tenant id"
},
"subscriptions": {
"additionalProperties": {
"$ref": "#/$defs/Subscription"
@ -55,6 +59,7 @@
"type": "object",
"required": [
"configPath",
"tenantId",
"subscriptions"
]
},

14
azure/az/config.yaml Normal file
View File

@ -0,0 +1,14 @@
# yaml-language-server: $schema=config.schema.json
configPath: .posh/config/azure
tenantId: xxxx-xx-xx-xx-xxxx
subscriptions:
development:
name: xxxx-xx-xx-xx-xxxx
clusters:
dev:
name: my-cluster
resourceGroup: my-resource-group
artifactories:
dev:
name: my-artifactory
resourceGroup: my-resource-group

View File

@ -6,7 +6,6 @@ import (
gokaziconfig "github.com/foomo/gokazi/pkg/config"
"github.com/foomo/gokazi/pkg/gokazi"
"github.com/foomo/posh-providers/onepassword"
"github.com/foomo/posh/pkg/env"
"github.com/foomo/posh/pkg/log"
"github.com/spf13/viper"
)
@ -60,7 +59,6 @@ func New(l log.Logger, op *onepassword.OnePassword, gk *gokazi.Gokazi, opts ...O
inst.gk.Add("beam.cluster."+key, gokaziconfig.Task{
Name: "cloudflared",
Description: fmt.Sprintf("Cloudflare tunnel to cluster: '%s' [:%d]", key, value.Port),
Cwd: env.ProjectRoot(),
Args: []string{
"access", "tcp",
"--hostname", value.Hostname,
@ -72,7 +70,6 @@ func New(l log.Logger, op *onepassword.OnePassword, gk *gokazi.Gokazi, opts ...O
inst.gk.Add("beam.database."+key, gokaziconfig.Task{
Name: "cloudflared",
Description: fmt.Sprintf("Cloudflare tunnel to database: '%s' [:%d]", key, value.Port),
Cwd: env.ProjectRoot(),
Args: []string{
"access", "tcp",
"--hostname", value.Hostname,

View File

@ -449,8 +449,8 @@ func (c *Command) execute(ctx context.Context, r *readline.Readline) error {
)
}
if cmd == "up" && cfgCluster.Confirm {
result, err := pterm.DefaultInteractiveConfirm.Show(fmt.Sprintf("⚠︎ Are you sure you want to deploy to: '%s:%s'?", cluster, fleet))
if slices.Contains([]string{"up", "down"}, cmd) && cfgCluster.Confirm {
result, err := pterm.DefaultInteractiveConfirm.Show(fmt.Sprintf("Are you sure you want to run the command against: '%s:%s'?", cluster, fleet))
if err != nil {
return err
} else if !result {