Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
78ea136
feat: init db in entrypoint of full image
tauu Mar 31, 2023
2102e3e
fix: quote user/pass variables in docker entrypoint
tauu Jun 27, 2023
a3f71d2
feat: read IMMUDB_PASSWORD from a file
tauu Jun 27, 2023
edf044e
fix: specify IMMUDB_PASSWORD_FILE env variable in dockerfile
tauu Jun 27, 2023
a75945b
feat: add user and password flags to immuadmin
tauu Jul 7, 2023
76e3f5e
chore: evaluate --non-interactive flag only once in prerun
tauu Jul 8, 2023
974a605
chore: remove usage of deprecated TokenService option in immuadmin
tauu Jul 8, 2023
5f8b0af
feat: add dir flag for program folder option to immuadmin
tauu Jul 12, 2023
4a46a67
chore: clarify error message about password-file flag
tauu Jul 12, 2023
d0213ad
chore: return errors during connect in immuadmin
tauu Jul 12, 2023
1d6c2bf
feat: enable setting dialOptions in immuadmin command line for testing
tauu Jul 12, 2023
b987a29
chore: run commandline disconnect command for immuadmin logout
tauu Jul 12, 2023
89242da
test: update login tests to incorporate new --password-file flag
tauu Jul 12, 2023
d72604b
test: add test for --database flag
tauu Jul 12, 2023
4311f00
test: unify the creation of test commandline for immuadmin
tauu Jul 12, 2023
1002ed5
chore: always initialize immuclient during pre run in immuadmin
tauu Jul 12, 2023
f184794
feat: use new OpenSession api for login / login cmds in immuadmin
tauu Jul 12, 2023
65e5715
test: reenable tests for database commands of immuadmin
tauu Jul 12, 2023
896000c
chore: fix copy paste error
tauu Jul 12, 2023
62f61fb
test: reactivate and update some user command test for immuadmin
tauu Jul 12, 2023
f4f8dda
feat: add an interactive shell to immuadmin
tauu Jul 13, 2023
51d6a77
chore: unify persistent pre and post runs of immuadmin commands
tauu Jul 13, 2023
43cfd8b
chore: use same commandline for all commands
tauu Jul 13, 2023
4a9e3f1
style: move newTestCommandLine to cmd_test
tauu Jul 13, 2023
506aa7f
chore: use same command setup in testing as in release
tauu Jul 13, 2023
d6e9edc
chore: move the default post run to the root command
tauu Jul 13, 2023
aac4f76
chore: remove persistent pre run function which is identical to that …
tauu Jul 13, 2023
3c5fdee
fix: remove u shortcode for username flag in immuadmin
tauu Jul 13, 2023
cfa40e3
chore: convert backup subcommand to use new session api
tauu Jul 13, 2023
f579591
test: reenable most tests for the backup subcommand
tauu Jul 13, 2023
360ebe0
chore: clean up backup tests
tauu Jul 13, 2023
bbfe75d
chore: remove no longer used function from CommanLineCli
tauu Jul 13, 2023
b8446d9
test: reenable basic commandline tests
tauu Jul 13, 2023
fc86a9c
style: move command line test to commandline_test file
tauu Jul 13, 2023
a50ebc6
feat: use non-interactive flag in backup and restore commands
tauu Jul 13, 2023
d7e2fbd
chore: remove usage message from error message in immuadmin shell
tauu Jul 13, 2023
912c226
chore: hide persistent flags of root command in help messages of immu…
tauu Jul 13, 2023
adc98d0
fix: always set commandline to interactive mode for immuadmin shell
tauu Jul 13, 2023
c470af5
fix: intercept errors in immuadmin shell to not quit the upon errors
tauu Jul 13, 2023
2f8207c
fix: consistently return error in run functions of immuadmin
tauu Jul 13, 2023
a9b4d53
fix: consistently return errors for backup and restore commands
tauu Jul 13, 2023
948e64b
chore: use new immuadmin flags in docker entrypoint
tauu Jul 14, 2023
4a372e4
fix: updated go.mod and go.sum
tauu Nov 5, 2025
297220a
fix: update go.sum
tauu Nov 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions build/Dockerfile.full
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ LABEL org.opencontainers.image.authors="Codenotary Inc. <[email protected]>"
COPY --from=build /src/immudb /usr/sbin/immudb
COPY --from=build /src/immuadmin /src/immuclient /usr/local/bin/
COPY --from=build "/etc/ssl/certs/ca-certificates.crt" "/etc/ssl/certs/ca-certificates.crt"
COPY tools/user_db/create_user_db.sh /usr/local/bin/create_user_db.sh

ARG IMMU_UID="3322"
ARG IMMU_GID="3322"
Expand All @@ -34,6 +35,10 @@ ENV IMMUDB_HOME="/usr/share/immudb" \
IMMUDB_DEVMODE="true" \
IMMUDB_MAINTENANCE="false" \
IMMUDB_ADMIN_PASSWORD="immudb" \
IMMUDB_USER="" \
IMMUDB_PASSWORD="" \
IMMUDB_PASSWORD_FILE="" \
IMMUDB_DATABASE="" \
IMMUDB_PGSQL_SERVER="true" \
IMMUADMIN_TOKENFILE="/var/lib/immudb/admin_token"

Expand All @@ -43,7 +48,11 @@ RUN addgroup --system --gid $IMMU_GID immu && \
mkdir -p "$IMMUDB_DIR" && \
chown -R immu:immu "$IMMUDB_HOME" "$IMMUDB_DIR" && \
chmod -R 777 "$IMMUDB_HOME" "$IMMUDB_DIR" && \
chmod +x /usr/sbin/immudb /usr/local/bin/immuadmin /usr/local/bin/immuclient
chmod +x /usr/sbin/immudb /usr/local/bin/immuadmin /usr/local/bin/immuclient && \
mkdir -p /var/run/immudb && \
chown immu:immu /var/run/immudb && \
chmod 775 /var/run/immudb && \
chmod 555 /usr/local/bin/create_user_db.sh

EXPOSE 3322
EXPOSE 9497
Expand All @@ -52,4 +61,4 @@ EXPOSE 5432

HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "/usr/local/bin/immuadmin", "status" ]
USER immu
ENTRYPOINT ["/usr/sbin/immudb"]
ENTRYPOINT ["/usr/local/bin/create_user_db.sh", "/usr/sbin/immudb"]
112 changes: 52 additions & 60 deletions cmd/immuadmin/command/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ limitations under the License.
package immuadmin

import (
"context"
"errors"
"fmt"
stdos "os"
Expand All @@ -32,8 +31,6 @@ import (

c "github.com/codenotary/immudb/cmd/helper"
"github.com/codenotary/immudb/pkg/auth"
"github.com/codenotary/immudb/pkg/client/homedir"
"github.com/codenotary/immudb/pkg/client/tokenservice"
"github.com/codenotary/immudb/pkg/fs"
"github.com/codenotary/immudb/pkg/immuos"
"github.com/codenotary/immudb/pkg/server"
Expand Down Expand Up @@ -70,24 +67,19 @@ type Backupper interface {
}

type commandlineBck struct {
commandline
*commandline
Backupper
c.TerminalReader
}

func newCommandlineBck(os immuos.OS) (*commandlineBck, error) {
b, err := newBackupper(os)
func newCommandlineBck(cmdl *commandline) (*commandlineBck, error) {
b, err := newBackupper(cmdl.os)
if err != nil {
return nil, err
}
cl := commandline{}
cl.config.Name = "immuadmin"
cl.passwordReader = c.DefaultPasswordReader
cl.context = context.Background()
cl.os = os
tr := c.NewTerminalReader(stdos.Stdin)

return &commandlineBck{cl, b, tr}, nil
return &commandlineBck{cmdl, b, tr}, nil
}

func (clb *commandlineBck) Register(rootCmd *cobra.Command) *cobra.Command {
Expand All @@ -97,27 +89,32 @@ func (clb *commandlineBck) Register(rootCmd *cobra.Command) *cobra.Command {
return rootCmd
}

func (cl *commandlineBck) ConfigChain(post func(cmd *cobra.Command, args []string) error) func(cmd *cobra.Command, args []string) (err error) {
return func(cmd *cobra.Command, args []string) (err error) {
if err = cl.config.LoadConfig(cmd); err != nil {
return err
}
// here all command line options and services need to be configured by options retrieved from viper
cl.options = Options()
cl.ts = tokenservice.NewFileTokenService().WithHds(homedir.NewHomedirService()).WithTokenFileName(cl.options.TokenFileName)
if post != nil {
return post(cmd, args)
}
return nil
func (cl *commandlineBck) askYN(prompt string, defaultValue string) (string, error) {
fmt.Print(prompt)
switch defaultValue {
case "y":
fallthrough
case "Y":
fmt.Print(" [Y/n]: ")
case "n":
fallthrough
case "N":
fmt.Print(" [y/N]: ")
default:
fmt.Print(" [y/n]: ")
}
// Always answer yes in non-interactive mode.
if cl.nonInteractive {
return "Y", nil
}
return cl.TerminalReader.ReadFromTerminalYN(defaultValue)
}

func (cl *commandlineBck) dumpToFile(cmd *cobra.Command) {
ccmd := &cobra.Command{
Use: "dump [file]",
Short: "Dump database content to a file",
PersistentPreRunE: cl.ConfigChain(cl.checkLoggedInAndConnect),
PersistentPostRun: cl.disconnect,
PersistentPreRunE: cl.ConfigChain(cl.connect),
RunE: func(cmd *cobra.Command, args []string) error {
filename := fmt.Sprint("immudb_" + time.Now().Format("2006-01-02_15-04-05") + ".bkp")
if len(args) > 0 {
Expand Down Expand Up @@ -158,35 +155,28 @@ func (cl *commandlineBck) backup(cmd *cobra.Command) {
Short: "Make a copy of the database files and folders",
Long: "Pause the immudb server, create and save on the server machine a snapshot " +
"of the database files and folders (zip on Windows, tar.gz on Linux or uncompressed).",
PersistentPreRunE: cl.ConfigChain(nil),
RunE: func(cmd *cobra.Command, args []string) error {
dbDir, err := cmd.Flags().GetString("dbdir")
if err != nil {
cl.quit(err)
return nil
return err
}
if err = cl.mustNotBeWorkingDir(dbDir); err != nil {
cl.quit(err)
return nil
return err
}
manualStopStart, err := cmd.Flags().GetBool("manual-stop-start")
if err != nil {
cl.quit(err)
return nil
return err
}
uncompressed, err := cmd.Flags().GetBool("uncompressed")
if err != nil {
cl.quit(err)
return nil
return err
}
if err := cl.askUserConfirmation("backup", manualStopStart); err != nil {
cl.quit(err)
return nil
if err := cl.askUserConfirmation(cmd, "backup", manualStopStart); err != nil {
return err
}
backupPath, err := cl.offlineBackup(dbDir, uncompressed, manualStopStart)
if err != nil {
cl.quit(err)
return nil
return err
}
fmt.Printf("Database backup created: %s\n", backupPath)
return nil
Expand All @@ -206,27 +196,22 @@ func (cl *commandlineBck) restore(cmd *cobra.Command) {
Short: "Restore the database from a snapshot archive or folder",
Long: "Pause the immudb server and restore the database files and folders from a snapshot " +
"file (zip or tar.gz) or folder (uncompressed) residing on the server machine.",
PersistentPreRunE: cl.ConfigChain(nil),
RunE: func(cmd *cobra.Command, args []string) error {
snapshotPath := args[0]
dbDir, err := cmd.Flags().GetString("dbdir")
if err != nil {
cl.quit(err)
return nil
return err
}
manualStopStart, err := cmd.Flags().GetBool("manual-stop-start")
if err != nil {
cl.quit(err)
return nil
return err
}
if err := cl.askUserConfirmation("restore", manualStopStart); err != nil {
cl.quit(err)
return nil
if err := cl.askUserConfirmation(cmd, "restore", manualStopStart); err != nil {
return err
}
autoBackupPath, err := cl.offlineRestore(snapshotPath, dbDir, manualStopStart)
if err != nil {
cl.quit(err)
return nil
return err
}
fmt.Printf("Database restored from backup %s\n", snapshotPath)
fmt.Printf("A backup of the previous database has been also created: %s\n", autoBackupPath)
Expand All @@ -239,30 +224,37 @@ func (cl *commandlineBck) restore(cmd *cobra.Command) {
cmd.AddCommand(ccmd)
}

func (cl *commandlineBck) askUserConfirmation(process string, manualStopStart bool) error {
func (cl *commandlineBck) askUserConfirmation(cmd *cobra.Command, process string, manualStopStart bool) error {
if !manualStopStart {
fmt.Printf(
prompt := fmt.Sprintf(
"Server will be stopped and then restarted during the %s process.\n"+
"NOTE: If the backup process is forcibly interrupted, a manual restart "+
"of the immudb service may be needed.\n"+
"Are you sure you want to proceed? [y/N]: ", process)
answer, err := cl.ReadFromTerminalYN("N")
"Are you sure you want to proceed?", process)
answer, err := cl.askYN(prompt, "N")
if err != nil || !(strings.ToUpper("Y") == strings.TrimSpace(strings.ToUpper(answer))) {
return errors.New("Canceled")

}
pass, err := cl.passwordReader.Read("Enter admin password:")
pass, err := cl.getPassword(cmd, "password-file", "Enter admin password: ")
// pass, err := cl.passwordReader.Read("Enter admin password:")
if err != nil {
return err
}
_ = cl.checkLoggedInAndConnect(nil, nil)
defer cl.disconnect(nil, nil)
if _, err = cl.immuClient.Login(cl.context, []byte(auth.SysAdminUsername), pass); err != nil {
// Get the selected database for the session.
database, err := cmd.Flags().GetString("database")
if err != nil {
return err
}
// Verify the user may log into the database.
err = cl.openSession([]byte(auth.SysAdminUsername), pass, database)
if err != nil {
return err
}
cl.disconnect(nil, nil)
} else {
fmt.Print("Please make sure the immudb server is not running before proceeding. Are you sure you want to proceed? [y/N]: ")
answer, err := cl.ReadFromTerminalYN("N")
prompt := fmt.Sprint("Please make sure the immudb server is not running before proceeding. Are you sure you want to proceed?")
answer, err := cl.askYN(prompt, "N")
if err != nil || !(strings.ToUpper("Y") == strings.TrimSpace(strings.ToUpper(answer))) {
return errors.New("Canceled")
}
Expand Down
Loading
Loading