zone

package
v1.56.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 7, 2025 License: MIT Imports: 22 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ChangePrimaryNameserversCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:   "change-primary-nameservers --primary-nameservers-file <file> <zone>",
			Short: "Changes the primary nameservers of a secondary Zone",
			Long: `Changes the primary nameservers of a secondary Zone.

Input file has to be in JSON format. You can find the schema at https://docs.hetzner.cloud/reference/cloud#zone-actions-change-a-zone-primary-nameservers

Example file content:

[
  {
    "address": "203.0.113.10"
  },
  {
    "address": "203.0.113.11",
    "port": 5353
  },
  {
    "address": "203.0.113.12",
    "tsig_algorithm": "hmac-sha256",
    "tsig_key": "example-key"
  }
]`,
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.Zone().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}

		cmd.Flags().String("primary-nameservers-file", "", "JSON file containing the new primary nameservers. (use - to read from stdin)")
		_ = cmd.MarkFlagRequired("primary-nameservers-file")
		_ = cmd.MarkFlagFilename("primary-nameservers-file", "json")

		return cmd
	},
	Run: func(s state.State, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		idOrName, err := util.ParseZoneIDOrName(idOrName)
		if err != nil {
			return fmt.Errorf("failed to convert Zone name to ascii: %w", err)
		}

		zone, _, err := s.Client().Zone().Get(s, idOrName)
		if err != nil {
			return err
		}
		if zone == nil {
			return fmt.Errorf("Zone not found: %s", idOrName)
		}

		var opts hcloud.ZoneChangePrimaryNameserversOpts

		file, _ := cmd.Flags().GetString("primary-nameservers-file")
		opts.PrimaryNameservers, err = parsePrimaryNameservers(file)
		if err != nil {
			return err
		}

		action, _, err := s.Client().Zone().ChangePrimaryNameservers(s, zone, opts)
		if err != nil {
			return err
		}
		if err := s.WaitForActions(s, cmd, action); err != nil {
			return err
		}

		cmd.Printf("Primary nameservers for Zone %s updated\n", zone.Name)
		return nil
	},
	Experimental: experimental.DNS,
}
View Source
var ChangeTTLCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "change-ttl --ttl <ttl> <zone>",
			Short:                 "Changes the default Time To Live (TTL) of a Zone",
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.Zone().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}

		cmd.Flags().Int("ttl", 3600, "Default Time To Live (TTL) of the Zone (required)")
		_ = cmd.MarkFlagRequired("ttl")

		return cmd
	},
	Run: func(s state.State, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		idOrName, err := util.ParseZoneIDOrName(idOrName)
		if err != nil {
			return fmt.Errorf("failed to convert Zone name to ascii: %w", err)
		}

		zone, _, err := s.Client().Zone().Get(s, idOrName)
		if err != nil {
			return err
		}
		if zone == nil {
			return fmt.Errorf("Zone not found: %s", idOrName)
		}

		ttl, _ := cmd.Flags().GetInt("ttl")
		opts := hcloud.ZoneChangeTTLOpts{TTL: ttl}

		action, _, err := s.Client().Zone().ChangeTTL(s, zone, opts)
		if err != nil {
			return err
		}

		if err := s.WaitForActions(s, cmd, action); err != nil {
			return err
		}

		cmd.Printf("Changed default TTL on Zone %s\n", zone.Name)
		return nil
	},
	Experimental: experimental.DNS,
}
View Source
var CreateCmd = base.CreateCmd[*hcloud.Zone]{
	BaseCobraCommand: func(_ hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "create [options] --name <name> [--mode secondary --primary-nameservers <file>]",
			Short:                 "Create a Zone",
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}
		cmd.Flags().String("name", "", "Zone name (required)")
		_ = cmd.MarkFlagRequired("name")

		cmd.Flags().String("mode", "primary", "Mode of the Zone (primary, secondary)")
		_ = cmd.RegisterFlagCompletionFunc("mode", cmpl.SuggestCandidates(string(hcloud.ZoneModePrimary), string(hcloud.ZoneModeSecondary)))

		cmd.Flags().Int("ttl", 0, "Default Time To Live (TTL) of the Zone")

		cmd.Flags().StringToString("label", nil, "User-defined labels ('key=value') (can be specified multiple times)")

		cmd.Flags().StringSlice("enable-protection", []string{}, "Enable protection (delete) (default: none)")
		_ = cmd.RegisterFlagCompletionFunc("enable-protection", cmpl.SuggestCandidates("delete"))

		cmd.Flags().String("primary-nameservers-file", "", "JSON file containing the new primary nameservers. (See 'hcloud zone change-primary-nameservers -h' for help)")
		_ = cmd.MarkFlagFilename("primary-nameservers-file", "json")

		cmd.Flags().String("zonefile", "", "Zone file in BIND (RFC 1034/1035) format (use - to read from stdin)")
		_ = cmd.MarkFlagFilename("zonefile")

		return cmd
	},
	Run: func(s state.State, cmd *cobra.Command, _ []string) (*hcloud.Zone, any, error) {
		name, _ := cmd.Flags().GetString("name")
		mode, _ := cmd.Flags().GetString("mode")
		labels, _ := cmd.Flags().GetStringToString("label")
		protection, _ := cmd.Flags().GetStringSlice("enable-protection")

		name, err := util.ParseZoneIDOrName(name)
		if err != nil {
			return nil, nil, fmt.Errorf("failed to convert Zone name to ascii: %w", err)
		}

		switch mode {
		case string(hcloud.ZoneModePrimary), string(hcloud.ZoneModeSecondary):
		default:
			return nil, nil, fmt.Errorf("unknown Zone mode: %s", mode)
		}

		protectionOpts, err := getChangeProtectionOpts(true, protection)
		if err != nil {
			return nil, nil, err
		}

		createOpts := hcloud.ZoneCreateOpts{
			Name:   name,
			Mode:   hcloud.ZoneMode(mode),
			Labels: labels,
		}

		if cmd.Flags().Changed("primary-nameservers-file") {
			file, err := cmd.Flags().GetString("primary-nameservers-file")
			if err != nil {
				return nil, nil, err
			}

			nameservers, err := parsePrimaryNameservers(file)
			if err != nil {
				return nil, nil, err
			}

			for _, ns := range nameservers {
				createOpts.PrimaryNameservers = append(createOpts.PrimaryNameservers, hcloud.ZoneCreateOptsPrimaryNameserver{
					Address:       ns.Address,
					Port:          ns.Port,
					TSIGAlgorithm: ns.TSIGAlgorithm,
					TSIGKey:       ns.TSIGKey,
				})
			}
		}

		if cmd.Flags().Changed("ttl") {
			ttl, _ := cmd.Flags().GetInt("ttl")
			createOpts.TTL = &ttl
		}

		if cmd.Flags().Changed("zonefile") {
			if createOpts.Mode == hcloud.ZoneModeSecondary {
				return nil, nil, fmt.Errorf("Zones in secondary mode can not be created from a zone file")
			}

			zonefile, _ := cmd.Flags().GetString("zonefile")
			createOpts.Zonefile, err = readZonefile(zonefile)
			if err != nil {
				return nil, nil, err
			}
		}

		result, _, err := s.Client().Zone().Create(s, createOpts)
		if err != nil {
			return nil, nil, err
		}

		if err := s.WaitForActions(s, cmd, result.Action); err != nil {
			return nil, nil, err
		}
		cmd.Printf("Zone %s created\n", result.Zone.Name)

		if err := changeProtection(s, cmd, result.Zone, true, protectionOpts); err != nil {
			return nil, nil, err
		}

		zone, _, err := s.Client().Zone().GetByID(s, result.Zone.ID)
		if err != nil {
			return nil, nil, err
		}

		return zone, util.Wrap("zone", hcloud.SchemaFromZone(zone)), nil
	},
	Experimental: experimental.DNS,
}
View Source
var DeleteCmd = base.DeleteCmd{
	ResourceNameSingular: "Zone",
	ResourceNamePlural:   "Zones",
	ShortDescription:     "Delete a Zone",
	NameSuggestions:      func(c hcapi2.Client) func() []string { return c.Zone().Names },
	Fetch: func(s state.State, _ *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
		idOrName, err := util.ParseZoneIDOrName(idOrName)
		if err != nil {
			return nil, nil, fmt.Errorf("failed to convert Zone name to ascii: %w", err)
		}

		return s.Client().Zone().Get(s, idOrName)
	},
	Delete: func(s state.State, _ *cobra.Command, resource interface{}) (*hcloud.Action, error) {
		zone := resource.(*hcloud.Zone)
		res, _, err := s.Client().Zone().Delete(s, zone)
		if err != nil {
			return nil, err
		}
		return res.Action, nil
	},
	Experimental: experimental.DNS,
}
View Source
var DescribeCmd = base.DescribeCmd[*hcloud.Zone]{
	ResourceNameSingular: "Zone",
	ShortDescription:     "Describe a Zone",
	NameSuggestions:      func(c hcapi2.Client) func() []string { return c.Zone().Names },
	Fetch: func(s state.State, _ *cobra.Command, idOrName string) (*hcloud.Zone, interface{}, error) {
		idOrName, err := util.ParseZoneIDOrName(idOrName)
		if err != nil {
			return nil, nil, fmt.Errorf("failed to convert Zone name to ascii: %w", err)
		}

		zone, _, err := s.Client().Zone().Get(s, idOrName)
		if err != nil {
			return nil, nil, err
		}

		return zone, hcloud.SchemaFromZone(zone), nil
	},
	PrintText: func(_ state.State, _ *cobra.Command, out io.Writer, zone *hcloud.Zone) error {

		name := util.DisplayZoneName(zone.Name)
		if name != zone.Name {
			name = fmt.Sprintf("%s (IDNA: %s)", name, zone.Name)
		}

		fmt.Fprintf(out, "ID:\t%d\n", zone.ID)
		fmt.Fprintf(out, "Name:\t%s\n", name)
		fmt.Fprintf(out, "Created:\t%s (%s)\n", util.Datetime(zone.Created), humanize.Time(zone.Created))
		fmt.Fprintf(out, "Mode:\t%s\n", zone.Mode)
		fmt.Fprintf(out, "Status:\t%s\n", zone.Status)
		fmt.Fprintf(out, "TTL:\t%d\n", zone.TTL)
		fmt.Fprintf(out, "Registrar:\t%s\n", zone.Registrar)
		fmt.Fprintf(out, "Record Count:\t%d\n", zone.RecordCount)

		fmt.Fprintln(out)
		fmt.Fprintf(out, "Protection:\n")
		fmt.Fprintf(out, "  Delete:\t%s\n", util.YesNo(zone.Protection.Delete))

		fmt.Fprintln(out)
		util.DescribeLabels(out, zone.Labels, "")

		fmt.Fprintln(out)
		fmt.Fprintf(out, "Authoritative Nameservers:\n")
		fmt.Fprintf(out, "  Assigned:\n")
		if len(zone.AuthoritativeNameservers.Assigned) > 0 {
			for _, srv := range zone.AuthoritativeNameservers.Assigned {
				fmt.Fprintf(out, "    - %s\n", srv)
			}
		} else {
			fmt.Fprintf(out, "    No assigned nameservers\n")
		}

		fmt.Fprintf(out, "  Delegated:\n")
		if len(zone.AuthoritativeNameservers.Delegated) > 0 {
			for _, srv := range zone.AuthoritativeNameservers.Delegated {
				fmt.Fprintf(out, "    - %s\n", srv)
			}
		} else {
			fmt.Fprintf(out, "    No delegated nameservers\n")
		}
		fmt.Fprintf(out, "  Delegation last check:\t%s (%s)\n",
			util.Datetime(zone.AuthoritativeNameservers.DelegationLastCheck),
			humanize.Time(zone.AuthoritativeNameservers.DelegationLastCheck))
		fmt.Fprintf(out, "  Delegation status:\t%s\n", zone.AuthoritativeNameservers.DelegationStatus)

		if zone.Mode == hcloud.ZoneModeSecondary {
			fmt.Fprintf(out, "Primary nameservers:\t\n")
			for _, ns := range zone.PrimaryNameservers {
				fmt.Fprintf(out, "  - Address:\t%s\n", ns.Address)
				fmt.Fprintf(out, "    Port:\t%d\n", ns.Port)
				if ns.TSIGAlgorithm != "" {
					fmt.Fprintf(out, "    TSIG Algorithm:\t%s\n", ns.TSIGAlgorithm)
				}
				if ns.TSIGKey != "" {
					fmt.Fprintf(out, "    TSIG Key:\t%s\n", ns.TSIGKey)
				}
			}
		}
		return nil
	},
	Experimental: experimental.DNS,
}
View Source
var DisableProtectionCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		return &cobra.Command{
			Use:   "disable-protection <zone> delete",
			Args:  util.ValidateLenient,
			Short: "Disable resource protection for a Zone",
			ValidArgsFunction: cmpl.SuggestArgs(
				cmpl.SuggestCandidatesF(client.Zone().Names),
				cmpl.SuggestCandidates("delete"),
			),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}
	},
	Run: func(s state.State, cmd *cobra.Command, args []string) error {
		idOrName, levels := args[0], args[1:]

		idOrName, err := util.ParseZoneIDOrName(idOrName)
		if err != nil {
			return fmt.Errorf("failed to convert Zone name to ascii: %w", err)
		}

		zone, _, err := s.Client().Zone().Get(s, idOrName)
		if err != nil {
			return err
		}
		if zone == nil {
			return fmt.Errorf("Zone not found: %s", idOrName)
		}

		opts, err := getChangeProtectionOpts(false, levels)
		if err != nil {
			return err
		}

		return changeProtection(s, cmd, zone, false, opts)
	},
	Experimental: experimental.DNS,
}
View Source
var EnableProtectionCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		return &cobra.Command{
			Use:   "enable-protection <zone> delete",
			Args:  util.ValidateLenient,
			Short: "Enable resource protection for a Zone",
			ValidArgsFunction: cmpl.SuggestArgs(
				cmpl.SuggestCandidatesF(client.Zone().Names),
				cmpl.SuggestCandidates("delete"),
			),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}
	},
	Run: func(s state.State, cmd *cobra.Command, args []string) error {
		idOrName, levels := args[0], args[1:]

		idOrName, err := util.ParseZoneIDOrName(idOrName)
		if err != nil {
			return fmt.Errorf("failed to convert Zone name to ascii: %w", err)
		}

		zone, _, err := s.Client().Zone().Get(s, idOrName)
		if err != nil {
			return err
		}
		if zone == nil {
			return fmt.Errorf("Zone not found: %s", idOrName)
		}

		opts, err := getChangeProtectionOpts(true, levels)
		if err != nil {
			return err
		}

		return changeProtection(s, cmd, zone, true, opts)
	},
	Experimental: experimental.DNS,
}
View Source
var ExportZonefileCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "export-zonefile [options] <zone>",
			Short:                 "Returns a generated Zone file in BIND (RFC 1034/1035) format",
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.Zone().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}

		output.AddFlag(cmd, output.OptionJSON(), output.OptionYAML())
		return cmd
	},
	Run: func(s state.State, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		idOrName, err := util.ParseZoneIDOrName(idOrName)
		if err != nil {
			return fmt.Errorf("failed to convert Zone name to ascii: %w", err)
		}

		outputFlags := output.FlagsForCommand(cmd)

		zone, _, err := s.Client().Zone().Get(s, idOrName)
		if err != nil {
			return err
		}
		if zone == nil {
			return fmt.Errorf("Zone not found: %s", idOrName)
		}

		res, _, err := s.Client().Zone().ExportZonefile(s, zone)
		if err != nil {
			return err
		}

		schema := util.Wrap("zonefile", res.Zonefile)

		switch {
		case outputFlags.IsSet("json"):
			return util.DescribeJSON(cmd.OutOrStdout(), schema)
		case outputFlags.IsSet("yaml"):
			return util.DescribeYAML(cmd.OutOrStdout(), schema)
		default:
			cmd.Print(res.Zonefile)
		}
		return nil
	},
	Experimental: experimental.DNS,
}
View Source
var ImportZonefileCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "import-zonefile --zonefile <file> <zone>",
			Short:                 "Imports a zone file, replacing all Zone RRSets",
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.Zone().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}

		cmd.Flags().String("zonefile", "", "Zone file in BIND (RFC 1034/1035) format (use - to read from stdin)")
		_ = cmd.MarkFlagRequired("zonefile")
		_ = cmd.MarkFlagFilename("zonefile")

		output.AddFlag(cmd, output.OptionJSON(), output.OptionYAML())

		return cmd
	},
	Run: func(s state.State, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		idOrName, err := util.ParseZoneIDOrName(idOrName)
		if err != nil {
			return fmt.Errorf("failed to convert Zone name to ascii: %w", err)
		}

		zone, _, err := s.Client().Zone().Get(s, idOrName)
		if err != nil {
			return err
		}
		if zone == nil {
			return fmt.Errorf("Zone not found: %s", idOrName)
		}

		opts := hcloud.ZoneImportZonefileOpts{}

		zonefile, _ := cmd.Flags().GetString("zonefile")
		opts.Zonefile, err = readZonefile(zonefile)
		if err != nil {
			return err
		}

		action, _, err := s.Client().Zone().ImportZonefile(s, zone, opts)
		if err != nil {
			return err
		}

		if err := s.WaitForActions(s, cmd, action); err != nil {
			return err
		}

		cmd.Printf("Zone file for Zone %s imported\n", zone.Name)

		return nil
	},
	Experimental: experimental.DNS,
}
View Source
var LabelCmds = base.LabelCmds[*hcloud.Zone]{
	ResourceNameSingular:   "Zone",
	ShortDescriptionAdd:    "Add a label to a Zone",
	ShortDescriptionRemove: "Remove a label from a Zone",
	NameSuggestions:        func(c hcapi2.Client) func() []string { return c.Zone().Names },
	LabelKeySuggestions:    func(c hcapi2.Client) func(idOrName string) []string { return c.Zone().LabelKeys },
	Fetch: func(s state.State, idOrName string) (*hcloud.Zone, error) {
		idOrName, err := util.ParseZoneIDOrName(idOrName)
		if err != nil {
			return nil, fmt.Errorf("failed to convert Zone name to ascii: %w", err)
		}

		zone, _, err := s.Client().Zone().Get(s, idOrName)
		if err != nil {
			return nil, err
		}
		if zone == nil {
			return nil, fmt.Errorf("Zone not found: %s", idOrName)
		}

		return zone, nil
	},
	SetLabels: func(s state.State, zone *hcloud.Zone, labels map[string]string) error {
		opts := hcloud.ZoneUpdateOpts{
			Labels: labels,
		}
		_, _, err := s.Client().Zone().Update(s, zone, opts)
		return err
	},
	GetLabels: func(zone *hcloud.Zone) map[string]string {
		return zone.Labels
	},
	GetIDOrName: func(zone *hcloud.Zone) string {
		return zone.Name
	},
	Experimental: experimental.DNS,
}
View Source
var ListCmd = &base.ListCmd[*hcloud.Zone, schema.Zone]{
	ResourceNamePlural: "Zones",
	JSONKeyGetByName:   "zones",
	DefaultColumns:     []string{"id", "name", "status", "mode", "record_count", "age"},
	SortOption:         config.OptionSortZone,

	AdditionalFlags: func(cmd *cobra.Command) {
		cmd.Flags().String("mode", "", "Only Zones with this mode are displayed")
		_ = cmd.RegisterFlagCompletionFunc("mode", cmpl.SuggestCandidates(string(hcloud.ZoneModePrimary), string(hcloud.ZoneModeSecondary)))
	},

	Fetch: func(s state.State, flags *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]*hcloud.Zone, error) {
		opts := hcloud.ZoneListOpts{ListOpts: listOpts}
		if len(sorts) > 0 {
			opts.Sort = sorts
		}

		if flags.Changed("mode") {
			mode, _ := flags.GetString("mode")

			if hcloud.ZoneMode(mode) != hcloud.ZoneModePrimary && hcloud.ZoneMode(mode) != hcloud.ZoneModeSecondary {
				return nil, fmt.Errorf("unknown Zone mode: %s", mode)
			}

			opts.Mode = hcloud.ZoneMode(mode)
		}

		return s.Client().Zone().AllWithOpts(s, opts)
	},

	OutputTable: func(t *output.Table[*hcloud.Zone], _ hcapi2.Client) {
		t.
			AddAllowedFields(&hcloud.Zone{}).
			AddFieldFn("name", func(zone *hcloud.Zone) string {
				return util.DisplayZoneName(zone.Name)
			}).
			AddFieldFn("name_idna", func(zone *hcloud.Zone) string {
				return zone.Name
			}).
			AddFieldFn("primary_nameservers", func(zone *hcloud.Zone) string {
				addressAndPorts := make([]string, 0, len(zone.PrimaryNameservers))
				for _, ns := range zone.PrimaryNameservers {

					addressAndPorts = append(addressAndPorts, net.JoinHostPort(ns.Address, strconv.Itoa(ns.Port)))
				}

				return strings.Join(addressAndPorts, ", ")
			}).
			AddFieldFn("authoritative_nameservers", func(zone *hcloud.Zone) string {
				return strings.Join(zone.AuthoritativeNameservers.Assigned, ", ")
			}).
			AddFieldFn("protection", func(zone *hcloud.Zone) string {
				var protection []string
				if zone.Protection.Delete {
					protection = append(protection, "delete")
				}
				return strings.Join(protection, ", ")
			}).
			AddFieldFn("labels", func(zone *hcloud.Zone) string {
				return util.LabelsToString(zone.Labels)
			}).
			AddFieldFn("created", func(zone *hcloud.Zone) string {
				return util.Datetime(zone.Created)
			}).
			AddFieldFn("age", func(zone *hcloud.Zone) string {
				return util.Age(zone.Created, time.Now())
			})
	},

	Schema: hcloud.SchemaFromZone,

	Experimental: experimental.DNS,
}

Functions

func NewCommand

func NewCommand(s state.State) *cobra.Command

Types

This section is empty.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL