download set with c= to match every host of a cluster

This commit is contained in:
Mikaël Cluseau
2026-06-17 22:20:48 +02:00
parent d975836adf
commit f6b301c9a0
6 changed files with 54 additions and 27 deletions
+33 -4
View File
@@ -15,6 +15,8 @@ import (
restful "github.com/emicklei/go-restful" restful "github.com/emicklei/go-restful"
"github.com/pierrec/lz4" "github.com/pierrec/lz4"
"m.cluseau.fr/go/httperr" "m.cluseau.fr/go/httperr"
"novit.tech/direktil/pkg/localconfig"
) )
func globMatch(pattern, value string) bool { func globMatch(pattern, value string) bool {
@@ -27,10 +29,22 @@ type DownloadSet struct {
Items []DownloadSetItem Items []DownloadSetItem
} }
func (s DownloadSet) Contains(kind, name, asset string) bool { func (s DownloadSet) Contains(cfg *localconfig.Config, kind, name, asset string) bool {
for _, item := range s.Items { for _, item := range s.Items {
if item.Kind == kind && globMatch(item.Name, name) && if item.Kind != kind || !slices.Contains(item.Assets, asset) {
slices.Contains(item.Assets, asset) { continue
}
// c=<cluster> matches any host of the given cluster
if kind == "host" && strings.HasPrefix(item.Name, "c=") {
host := hostOrTemplate(cfg, name)
if host != nil && host.ClusterName == item.Name[2:] {
return true
}
continue
}
if globMatch(item.Name, name) {
return true return true
} }
} }
@@ -233,7 +247,13 @@ func wsDownloadSetAsset(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name") name := req.PathParameter("name")
asset := req.PathParameter("asset") asset := req.PathParameter("asset")
if !set.Contains(kind, name, asset) { cfg, err2 := readConfig()
if err2 != nil {
wsError(resp, err2)
return
}
if !set.Contains(cfg, kind, name, asset) {
wsNotFound(resp) wsNotFound(resp)
return return
} }
@@ -273,12 +293,21 @@ func wsDownloadSet(req *restful.Request, resp *restful.Response) {
} }
case "host": case "host":
section = "Host" section = "Host"
if strings.HasPrefix(item.Name, "c=") {
clusterName := item.Name[2:]
for _, h := range cfg.Hosts {
if h.ClusterName == clusterName {
names = append(names, h.Name)
}
}
} else {
for _, h := range cfg.Hosts { for _, h := range cfg.Hosts {
if globMatch(item.Name, h.Name) { if globMatch(item.Name, h.Name) {
names = append(names, h.Name) names = append(names, h.Name)
} }
} }
} }
}
for _, name := range names { for _, name := range names {
buf.WriteString("<p>") buf.WriteString("<p>")
@@ -4,16 +4,16 @@ const Cluster = {
template: ` template: `
<ClusterAccess :cluster="cluster" :token="token" :state="state" /> <ClusterAccess :cluster="cluster" :token="token" :state="state" />
<h3>Tokens</h3> <ClusterCAs :cluster="cluster" :token="token" />
<h3>Secrets</h3>
<h4>Tokens</h4>
<section class="links"> <section class="links">
<GetCopy v-for="n in cluster.Tokens" :token="token" :name="n" :href="'/clusters/'+cluster.Name+'/tokens/'+n" /> <GetCopy v-for="n in cluster.Tokens" :token="token" :name="n" :href="'/clusters/'+cluster.Name+'/tokens/'+n" />
</section> </section>
<h4>Passwords</h4>
<h3>Passwords</h3>
<section class="links"> <section class="links">
<GetCopy v-for="n in cluster.Passwords" :token="token" :name="n" :href="'/clusters/'+cluster.Name+'/passwords/'+n" /> <GetCopy v-for="n in cluster.Passwords" :token="token" :name="n" :href="'/clusters/'+cluster.Name+'/passwords/'+n" />
</section> </section>
<ClusterCAs :cluster="cluster" :token="token" />
` `
} }
@@ -79,12 +79,11 @@ const ClusterAccess = {
generateDownloadSet() { generateDownloadSet() {
event.preventDefault() event.preventDefault()
const hosts = this.hostCount ? (this.state.Hosts||[]).filter(h => h.Cluster == this.cluster.Name) : [] const items = [{
const items = hosts.map(h => ({
Kind: "host", Kind: "host",
Name: h.Name, Name: "c=" + this.cluster.Name,
Assets: this.selectedAssetList, Assets: this.selectedAssetList,
})) }]
fetch('/sign-download-set', { fetch('/sign-download-set', {
method: 'POST', method: 'POST',
+2 -2
View File
@@ -13,9 +13,9 @@
<script src="/ui/app-e7fb26679b9aa0f2.js" defer integrity="sha384-4oRQalb7IIBcqQzfDkeCj53qYOP6dLsTwqcjnm3EiBa92oNDD3chUw38W2gEC+3p" type="module"></script> <script src="/ui/app-e7fb26679b9aa0f2.js" defer integrity="sha384-4oRQalb7IIBcqQzfDkeCj53qYOP6dLsTwqcjnm3EiBa92oNDD3chUw38W2gEC+3p" type="module"></script>
<script src="/ui/Downloads-25b2e1f4aeaaff61.js" integrity="sha384-MP2lefUuPRss5MQ11H5SzGp8Gmy+hPAdeEC79h4c/SDAp4qFGUjhxBtQL8rnP38U"></script> <script src="/ui/Downloads-25b2e1f4aeaaff61.js" integrity="sha384-MP2lefUuPRss5MQ11H5SzGp8Gmy+hPAdeEC79h4c/SDAp4qFGUjhxBtQL8rnP38U"></script>
<script src="/ui/GetCopy-7e3c9678f9647d40.js" integrity="sha384-LzxUXylxE/t25HyTch8y2qvKcehvP2nqCo37swIBGEKZZUzHVJVQrS5UJDWNskTA"></script> <script src="/ui/GetCopy-7e3c9678f9647d40.js" integrity="sha384-LzxUXylxE/t25HyTch8y2qvKcehvP2nqCo37swIBGEKZZUzHVJVQrS5UJDWNskTA"></script>
<script src="/ui/ClusterAccess-fede0ff535b7cf.js" integrity="sha384-Np8ntVwZ/f0nRYPByzkvya8zF+PQHEDtThOGTtlwyWybtxn6RqYsw6R++bSlv37I"></script> <script src="/ui/ClusterAccess-e67af72c976d642c.js" integrity="sha384-QU0xM0hvd7tVSJ42IVfmL0u0uJbzyZBrxn1vVbOh/15Xa80JK9j9VieoACGYFjx2"></script>
<script src="/ui/ClusterCAs-d6eba07c367b6306.js" integrity="sha384-2zV1VzNHw7hUS6SNIqDzIczma3Ixp3G9u6BJI4MtGHK4rNYWeCOOu9kttsZzkPYC"></script> <script src="/ui/ClusterCAs-d6eba07c367b6306.js" integrity="sha384-2zV1VzNHw7hUS6SNIqDzIczma3Ixp3G9u6BJI4MtGHK4rNYWeCOOu9kttsZzkPYC"></script>
<script src="/ui/Cluster-8864c22a73e68a3e.js" integrity="sha384-MCRzMDZhqeM2hXm8fJqnxw1IINE6eTGex3PvT5KnjVPdKXyINEcbK6Y/sfjY8Sqq"></script> <script src="/ui/Cluster-361bc6b76a062d88.js" integrity="sha384-msh65M8IktAuqPyO5c7GFLkRYTtN2wh5KN23SDNuC5m1gwPpuiEeY4qkr9g1bCi1"></script>
<script src="/ui/Host-61916516a854adff.js" integrity="sha384-/wh3KrC0sb4MT7ekO2U84rswxI42WSH/0jB4dbDaaGaGhX60xTEZHFsdQAf7UgTG"></script> <script src="/ui/Host-61916516a854adff.js" integrity="sha384-/wh3KrC0sb4MT7ekO2U84rswxI42WSH/0jB4dbDaaGaGhX60xTEZHFsdQAf7UgTG"></script>
<body> <body>
+5 -5
View File
@@ -4,16 +4,16 @@ const Cluster = {
template: ` template: `
<ClusterAccess :cluster="cluster" :token="token" :state="state" /> <ClusterAccess :cluster="cluster" :token="token" :state="state" />
<h3>Tokens</h3> <ClusterCAs :cluster="cluster" :token="token" />
<h3>Secrets</h3>
<h4>Tokens</h4>
<section class="links"> <section class="links">
<GetCopy v-for="n in cluster.Tokens" :token="token" :name="n" :href="'/clusters/'+cluster.Name+'/tokens/'+n" /> <GetCopy v-for="n in cluster.Tokens" :token="token" :name="n" :href="'/clusters/'+cluster.Name+'/tokens/'+n" />
</section> </section>
<h4>Passwords</h4>
<h3>Passwords</h3>
<section class="links"> <section class="links">
<GetCopy v-for="n in cluster.Passwords" :token="token" :name="n" :href="'/clusters/'+cluster.Name+'/passwords/'+n" /> <GetCopy v-for="n in cluster.Passwords" :token="token" :name="n" :href="'/clusters/'+cluster.Name+'/passwords/'+n" />
</section> </section>
<ClusterCAs :cluster="cluster" :token="token" />
` `
} }
+3 -4
View File
@@ -79,12 +79,11 @@ const ClusterAccess = {
generateDownloadSet() { generateDownloadSet() {
event.preventDefault() event.preventDefault()
const hosts = this.hostCount ? (this.state.Hosts||[]).filter(h => h.Cluster == this.cluster.Name) : [] const items = [{
const items = hosts.map(h => ({
Kind: "host", Kind: "host",
Name: h.Name, Name: "c=" + this.cluster.Name,
Assets: this.selectedAssetList, Assets: this.selectedAssetList,
})) }]
fetch('/sign-download-set', { fetch('/sign-download-set', {
method: 'POST', method: 'POST',