package kubernetes
import (
"errors"
"fmt"
"sync"
"sync/atomic"
"time"
"github.com/coredns/coredns/plugin/kubernetes/object"
api "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
)
const (
podIPIndex = "PodIP"
svcNameNamespaceIndex = "NameNamespace"
svcIPIndex = "ServiceIP"
epNameNamespaceIndex = "EndpointNameNamespace"
epIPIndex = "EndpointsIP"
)
type dnsController interface {
ServiceList() []*object.Service
EndpointsList() []*object.Endpoints
SvcIndex(string) []*object.Service
SvcIndexReverse(string) []*object.Service
PodIndex(string) []*object.Pod
EpIndex(string) []*object.Endpoints
EpIndexReverse(string) []*object.Endpoints
GetNodeByName(string) (*api.Node, error)
GetNamespaceByName(string) (*api.Namespace, error)
Run()
HasSynced() bool
Stop() error
// Modified returns the timestamp of the most recent changes
Modified() int64
}
type dnsControl struct {
// Modified tracks timestamp of the most recent changes
// It needs to be first because it is guaranteed to be 8-byte
// aligned ( we use sync.LoadAtomic with this )
modified int64
client kubernetes.Interface
selector labels.Selector
svcController cache.Controller
podController cache.Controller
epController cache.Controller
nsController cache.Controller
svcLister cache.Indexer
podLister cache.Indexer
epLister cache.Indexer
nsLister cache.Store
// stopLock is used to enforce only a single call to Stop is active.
// Needed because we allow stopping through an http endpoint and
// allowing concurrent stoppers leads to stack traces.
stopLock sync.Mutex
shutdown bool
stopCh chan struct{}
zones []string
endpointNameMode bool
}
type dnsControlOpts struct {
initPodCache bool
initEndpointsCache bool
resyncPeriod time.Duration
ignoreEmptyService bool
// Label handling.
labelSelector *meta.LabelSelector
selector labels.Selector
zones []string
endpointNameMode bool
}
// newDNSController creates a controller for CoreDNS.
func newdnsController(kubeClient kubernetes.Interface, opts dnsControlOpts) *dnsControl {
dns := dnsControl{
client: kubeClient,
selector: opts.selector,
stopCh: make(chan struct{}),
zones: opts.zones,
endpointNameMode: opts.endpointNameMode,
}
dns.svcLister, dns.svcController = object.NewIndexerInformer(
&cache.ListWatch{
ListFunc: serviceListFunc(dns.client, api.NamespaceAll, dns.selector),
WatchFunc: serviceWatchFunc(dns.client, api.NamespaceAll, dns.selector),
},
&api.Service{},
opts.resyncPeriod,
cache.ResourceEventHandlerFuncs{},
cache.Indexers{svcNameNamespaceIndex: svcNameNamespaceIndexFunc, svcIPIndex: svcIPIndexFunc},
object.ToService,
)
if opts.initPodCache {
dns.podLister, dns.podController = object.NewIndexerInformer(
&cache.ListWatch{
ListFunc: podListFunc(dns.client, api.NamespaceAll, dns.selector),
WatchFunc: podWatchFunc(dns.client, api.NamespaceAll, dns.selector),
},
&api.Pod{},
opts.resyncPeriod,
cache.ResourceEventHandlerFuncs{},
cache.Indexers{podIPIndex: podIPIndexFunc},
object.ToPod,
)
}
if opts.initEndpointsCache {
dns.epLister, dns.epController = object.NewIndexerInformer(
&cache.ListWatch{
ListFunc: endpointsListFunc(dns.client, api.NamespaceAll, dns.selector),
WatchFunc: endpointsWatchFunc(dns.client, api.NamespaceAll, dns.selector),
},
&api.Endpoints{},
opts.resyncPeriod,
cache.ResourceEventHandlerFuncs{},
cache.Indexers{epNameNamespaceIndex: epNameNamespaceIndexFunc, epIPIndex: epIPIndexFunc},
object.ToEndpoints)
}
dns.nsLister, dns.nsController = cache.NewInformer(
&cache.ListWatch{
ListFunc: namespaceListFunc(dns.client, dns.selector),
WatchFunc: namespaceWatchFunc(dns.client, dns.selector),
},
&api.Namespace{}, opts.resyncPeriod, cache.ResourceEventHandlerFuncs{})
return &dns
}
func podIPIndexFunc(obj interface{}) ([]string, error) {
p, ok := obj.(*object.Pod)
if !ok {
return nil, errObj
}
return []string{p.PodIP}, nil
}
func svcIPIndexFunc(obj interface{}) ([]string, error) {
svc, ok := obj.(*object.Service)
if !ok {
return nil, errObj
}
if len(svc.ExternalIPs) == 0 {
return []string{svc.ClusterIP}, nil
}
return append([]string{svc.ClusterIP}, svc.ExternalIPs...), nil
}
func svcNameNamespaceIndexFunc(obj interface{}) ([]string, error) {
s, ok := obj.(*object.Service)
if !ok {
return nil, errObj
}
return []string{s.Index}, nil
}
func epNameNamespaceIndexFunc(obj interface{}) ([]string, error) {
s, ok := obj.(*object.Endpoints)
if !ok {
return nil, errObj
}
return []string{s.Index}, nil
}
func epIPIndexFunc(obj interface{}) ([]string, error) {
ep, ok := obj.(*object.Endpoints)
if !ok {
return nil, errObj
}
return ep.IndexIP, nil
}
func serviceListFunc(c kubernetes.Interface, ns string, s labels.Selector) func(meta.ListOptions) (runtime.Object, error) {
return func(opts meta.ListOptions) (runtime.Object, error) {
if s != nil {
opts.LabelSelector = s.String()
}
listV1, err := c.CoreV1().Services(ns).List(opts)
return listV1, err
}
}
func podListFunc(c kubernetes.Interface, ns string, s labels.Selector) func(meta.ListOptions) (runtime.Object, error) {
return func(opts meta.ListOptions) (runtime.Object, error) {
if s != nil {
opts.LabelSelector = s.String()
}
listV1, err := c.CoreV1().Pods(ns).List(opts)
return listV1, err
}
}
func endpointsListFunc(c kubernetes.Interface, ns string, s labels.Selector) func(meta.ListOptions) (runtime.Object, error) {
return func(opts meta.ListOptions) (runtime.Object, error) {
if s != nil {
opts.LabelSelector = s.String()
}
listV1, err := c.CoreV1().Endpoints(ns).List(opts)
return listV1, err
}
}
func namespaceListFunc(c kubernetes.Interface, s labels.Selector) func(meta.ListOptions) (runtime.Object, error) {
return func(opts meta.ListOptions) (runtime.Object, error) {
if s != nil {
opts.LabelSelector = s.String()
}
listV1, err := c.CoreV1().Namespaces().List(opts)
return listV1, err
}
}
// Stop stops the controller.
func (dns *dnsControl) Stop() error {
dns.stopLock.Lock()
defer dns.stopLock.Unlock()
// Only try draining the workqueue if we haven't already.
if !dns.shutdown {
close(dns.stopCh)
dns.shutdown = true
return nil
}
return fmt.Errorf("shutdown already in progress")
}
// Run starts the controller.
func (dns *dnsControl) Run() {
go dns.svcController.Run(dns.stopCh)
if dns.epController != nil {
go dns.epController.Run(dns.stopCh)
}
if dns.podController != nil {
go dns.podController.Run(dns.stopCh)
}
go dns.nsController.Run(dns.stopCh)
<-dns.stopCh
}
// HasSynced calls on all controllers.
func (dns *dnsControl) HasSynced() bool {
a := dns.svcController.HasSynced()
b := true
if dns.epController != nil {
b = dns.epController.HasSynced()
}
c := true
if dns.podController != nil {
c = dns.podController.HasSynced()
}
d := dns.nsController.HasSynced()
return a && b && c && d
}
func (dns *dnsControl) ServiceList() (svcs []*object.Service) {
os := dns.svcLister.List()
for _, o := range os {
s, ok := o.(*object.Service)
if !ok {
continue
}
svcs = append(svcs, s)
}
return svcs
}
func (dns *dnsControl) EndpointsList() (eps []*object.Endpoints) {
os := dns.epLister.List()
for _, o := range os {
ep, ok := o.(*object.Endpoints)
if !ok {
continue
}
eps = append(eps, ep)
}
return eps
}
func (dns *dnsControl) PodIndex(ip string) (pods []*object.Pod) {
os, err := dns.podLister.ByIndex(podIPIndex, ip)
if err != nil {
return nil
}
for _, o := range os {
p, ok := o.(*object.Pod)
if !ok {
continue
}
pods = append(pods, p)
}
return pods
}
func (dns *dnsControl) SvcIndex(idx string) (svcs []*object.Service) {
os, err := dns.svcLister.ByIndex(svcNameNamespaceIndex, idx)
if err != nil {
return nil
}
for _, o := range os {
s, ok := o.(*object.Service)
if !ok {
continue
}
svcs = append(svcs, s)
}
return svcs
}
func (dns *dnsControl) SvcIndexReverse(ip string) (svcs []*object.Service) {
os, err := dns.svcLister.ByIndex(svcIPIndex, ip)
if err != nil {
return nil
}
for _, o := range os {
s, ok := o.(*object.Service)
if !ok {
continue
}
svcs = append(svcs, s)
}
return svcs
}
func (dns *dnsControl) EpIndex(idx string) (ep []*object.Endpoints) {
os, err := dns.epLister.ByIndex(epNameNamespaceIndex, idx)
if err != nil {
return nil
}
for _, o := range os {
e, ok := o.(*object.Endpoints)
if !ok {
continue
}
ep = append(ep, e)
}
return ep
}
func (dns *dnsControl) EpIndexReverse(ip string) (ep []*object.Endpoints) {
os, err := dns.epLister.ByIndex(epIPIndex, ip)
if err != nil {
return nil
}
for _, o := range os {
e, ok := o.(*object.Endpoints)
if !ok {
continue
}
ep = append(ep, e)
}
return ep
}
// GetNodeByName return the node by name. If nothing is found an error is
// returned. This query causes a roundtrip to the k8s API server, so use
// sparingly. Currently this is only used for Federation.
func (dns *dnsControl) GetNodeByName(name string) (*api.Node, error) {
v1node, err := dns.client.CoreV1().Nodes().Get(name, meta.GetOptions{})
return v1node, err
}
// GetNamespaceByName returns the namespace by name. If nothing is found an error is returned.
func (dns *dnsControl) GetNamespaceByName(name string) (*api.Namespace, error) {
os := dns.nsLister.List()
for _, o := range os {
ns, ok := o.(*api.Namespace)
if !ok {
continue
}
if name == ns.ObjectMeta.Name {
return ns, nil
}
}
return nil, fmt.Errorf("namespace not found")
}
func (dns *dnsControl) Modified() int64 {
unix := atomic.LoadInt64(&dns.modified)
return unix
}
// updateModified set dns.modified to the current time.
func (dns *dnsControl) updateModifed() {
unix := time.Now().Unix()
atomic.StoreInt64(&dns.modified, unix)
}
var errObj = errors.New("obj was not of the correct type")
torage-studio
feat/streaming-rendering
feat/style-obj
feat/test-utils
feat/xray-improvements
fetch-astro-pages-mvp
fix-408
fix-all-pages-key
fix-beta-ref
fix-create-ref
fix-netlify-edge
fix-next-basics
fix-nullish-slot-name
fix-s-island-fallback
fix-vite-asset
fix/actions-cookies
fix/actions-pending-timeout
fix/assets-types
fix/astro-config-refresh
fix/astro-html-escape-bug
fix/build-subpaths
fix/client-only-component-css
fix/client-scripts-windows
fix/config-migration-defaults
fix/container-directives
fix/dates
fix/db-integration-with-missing-config
fix/devtoolbar-data-unset
fix/empty-slots
fix/filepath-layer
fix/frontmatter-file-url
fix/head-propagation
fix/hmr-css-deps
fix/import-ts-errors
fix/main-build-failure
fix/map-file-404-logs
fix/mdx-named-slots
fix/middleware-import
fix/multi-images
fix/nested-get-collection-call
fix/preact-package-build-failure
fix/primary-key-optional
fix/regex-flags
fix/server-headers
fix/stable-renderer-order
fix/transaction-type
fix/vue-nested
fix/webapi-dev
fork/markdoc-poc-with-md-support
fork/markdoc-poc-with-parser
format-imports-run
formatting
forward-button
framework-agnostic-astro-components
fryuni/db-pluggable-backend
fryuni/test-route-setup-hook
fryuni/tracing-hooks
hippotastic/legitimate-bat
hoisted-script-ts
host-ssr-example-2
hostfornode
image-non-node
improve-base-handling
inline-hoisted-scripts-now
jn.convert-assertions-to-query-params
latest
live-loaders
main
mandar1jn/ci-repo-check
markdoc-embed-prototyping
markdown
markdown-poc
mdx-path
mk/render-slot-template-backup
move-default-md-code-component
mt/lit-DSD
mt/lit-regen
mt/parse-DSD
mt/router_refactoring
nate/new-blog-template
netlify-1
netlify-preview
new-adapter-api
next
next-render
no-more-vite-postprocess
no-more-vite-postprocess2
old-build
plt-1006/unified-and-mdx
plt-1768-trailing-slash-object
preact-shared-signals
process-env-override
progress-log
re-export-drivers
react-fast-refresh
redirects-priority2
redirects-ssg-object
refactor-how-client-directives-work
refactor/image-internals
refactor/markdoc-renderer
refactor/rendere-queue
refactor/sitemap
refactor/ssr-size
release/0.17
release/0.18
remote-cdn-link
remove-fs-abstraction
remove-start
restart-on-lock
revert-13008-renovate/all-minor-patch
revert-lockfile
route-manifest-adapter
sarah11918-image-errors
sarah11918-patch-2
sb-tests2
seroval
server-islands-children
session-docs
single-file-build-2
slash-404-hint
slot-bug-1
solid-ecosystem-pkg
spike/app-setup
spike/autonav
spike/codehike
spike/context
spike/csr
spike/default-content
spike/incremental
spike/incremental-ii
spike/markdown-wasm
spike/render
spike/streaming
spike/svg
sqlite-test
squeal
ssr-redirect
stream-buffer
streaming
telemetry-audit-1
test/new-integrations-demo
test/new-ssr-demo
top-level-exports-integrations
ts-in-hoisted-script
ts-no-err
upd-vite-vendored
upgrade-deps
v1-beta
vercel-test
vite-fork
vscode-astro-global
vt-follow-redirects
warn-exp-flag
win
windows-tests-beta
wip-assets
wip-component-api-2
wip-docs-components
wip-docs-reference-gen
wip-fetch-cache
wip-fun-flags
wip-icons
wip-logging
wip-logging-saved
wip-mdc
wip-mdx-to-astro-js
wip-preview-command-integrations
wip-setup-content
wip-smoke
wip-speed-up-markdown
wip-stage
wip/react-19-test
Unnamed repository; edit this file 'description' to name the repository.
Age Commit message (Collapse ) Author Files Lines
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix: update `vite` to latest version
* apply suggestion
Co-authored-by: ematipico <602478+ematipico@users.noreply.github.com>
* fix(i18n): return value from `preferredLocale`
* revert change
Co-authored-by: florian-lefebvre <69633530+florian-lefebvre@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* feat(cloudflare): add KV session storage support
* Change code block language to JSONC
* Comments
* Use user-defined binding name
* Use createCodegenDir
* Remove unused import
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* fix(deps): update astro dependencies
* fix types shenanigans
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
* wip
* fix(actions): avoid mutation of action context
* chore: revert changes
* add changeset
* Update .changeset/calm-beans-roll.md
Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev>
---------
Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat: update test
* feat: dynamic import
* chore: changeset
* Update .changeset/clever-tigers-dig.md
* fix: cache raw cookie value and decode when getting
* Add test
* Add comment
* fix: update vite
* use dedupe
* fix(app): call renderer when routes don't match
* chore: pick 404 exactly
* chore: pick route differently
Co-authored-by: ascorbic <213306+ascorbic@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix: better error handling on Stackblitz
* Remove unused imports
* rerun server island scripts when used with client router
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* feat(cloudflare): global env
* fix: test
* fix(deps): update astro client runtimes
* fix: pin vite-plugin-vue
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev>
Co-authored-by: sarah11918 <5098874+sarah11918@users.noreply.github.com>
* Add deprecation notice to Tailwind integration README
* Add changeset
* Use `[docs]` link style again
* update link to more direct content
---------
Co-authored-by: Sarah Rainsberger <5098874+sarah11918@users.noreply.github.com>
Co-authored-by: anaxite <89195061+anaxite@users.noreply.github.com>
Co-authored-by: sarah11918 <5098874+sarah11918@users.noreply.github.com>
Co-authored-by: Adammatthiesen <30383579+Adammatthiesen@users.noreply.github.com>
Co-authored-by: HiDeoo <494699+HiDeoo@users.noreply.github.com>
island (#13470)
* fix(preact,svelte): empty target container before rendering `client:only` island
* Remove log
* fix: don't attempt to move files after build with base
* Remove console
* Reword changeset
* Remove unused import
* fix(routing): don't add site to static redirects
* chore: fix canonical tag
* chore: fix canonical tag
Co-authored-by: ascorbic <213306+ascorbic@users.noreply.github.com>
* fix: set correct statusText for custom error pages
* Set conditionally
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>