Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cloudfuse service linux cmd #338

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open

Conversation

Dabnsky
Copy link
Contributor

@Dabnsky Dabnsky commented Oct 10, 2024

What type of Pull Request is this? (check all applicable)

  • Refactor
  • Feature
  • Bug Fix
  • Optimization
  • Documentation Update

Describe your changes in brief

This adds the following commands available to the cloudfuse executable:
cloudfuse service install
cloudfuse service uninstall

Checklist

  • Tested locally
  • Added new dependencies
  • Updated documentation
  • Added tests

Related Issues

  • Related Issue #
  • Closes #

@foodprocessor foodprocessor removed the request for review from brayan-trejo October 31, 2024 17:52
@Dabnsky Dabnsky marked this pull request as ready for review November 1, 2024 17:32
Comment on lines 63 to 64
Short: "Installs the startup process for Cloudfuse. Requires elevated permissions.",
Long: "Installs the startup process for Cloudfuse which remounts any active previously active mounts on startup. elevated permissions.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These descriptions should probably not refer to "the" startup process, since each call to install only affects a single mount, and we can use this command to make multiple "startup processes."

}

var installCmd = &cobra.Command{
Use: "install",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you require two arguments, the usage string should include those.

Comment on lines 79 to 83
// assumes dir is in cloudfuse repo dir
serviceData, err := collectServiceData(fmt.Sprintf("%s/setup/cloudfuse.service", dir))
if err != nil {
return fmt.Errorf("error collecting data from cloudfuse.service file due to the following error: [%s]", err)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For deployment, we need to add the cloudfuse.service file to the list of deployed files (in .goreleaser.yaml), and something like this should work. We may need to use filepath.Dir(os.Executable()) (documented here), instead of os.Getwd() to reliably get the path we need.

Comment on lines +94 to +98
isDirEmpty := common.IsDirectoryEmpty(mountPath)
if !isDirEmpty {
return fmt.Errorf("error, the mount path provided is not empty")
// TODO: add useage output upon failure with input
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to check this.

Copy link
Contributor Author

@Dabnsky Dabnsky Nov 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cloudfuse outputs an error and will not mount if the provided mount path is not empty

// TODO: add useage output upon failure with input
}

configExists := common.DirectoryExists(configPath)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although this works, I don't love that DirectoryExists is checking existence for a file.
I found another place where we check if the config file exists, and we use os.Stat directly:

if _, err := os.Stat(options.ConfigFile); errors.Is(err, fs.ErrNotExist) {
	return errors.New("config file does not exist")
}

},
}

var uninstallCmd = &cobra.Command{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The uninstall command will have to require the mount path to know which mount's startup service we need to remove.

Comment on lines 105 to 113
err = modifySericeFile(mountPath, dir)
if err != nil {
return fmt.Errorf("error when attempting to write defaults into service file: [%s]", err.Error())
}

err = modifySericeFile(configPath, dir)
if err != nil {
return fmt.Errorf("error when attempting to write defaults into service file: [%s]", err.Error())
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're creating a separate service file for each mount that the user wants to mount on startup, we'll want to

  • not change our template cloudfuse.service file (we should write the modified unit file data straight to the destination)
  • name each new service/unit file after the mount path, so they don't conflict, and so we can find them to remove them when uninstalling

Comment on lines 115 to 118
// 2. retrieve the newUser account from cloudfuse.service file and create it if it doesn't exist

serviceUser := serviceData["User"]
setUser(serviceUser)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Linux I don't think we need a dedicated user.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While failing to specify a user with the appropriate permissions doesn't stop the cloudfuse service from running and working, it opens up a large security risk involving the default permissions that are used when the service is run.


//--------------- command section ends

func collectServiceData(serviceFilePath string) (map[string]string, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know, but I feel like these helper functions could be a lot shorter, and more readable. I feel like these details should be abstracted away by a standard library function that does most or all of this for us...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I'm not sure anything specifically does this, but here is a go program that installs items with systemd that our design could be based around which is a lot cleaner. https://github.com/pioz/god

@Dabnsky Dabnsky marked this pull request as draft November 8, 2024 21:12
cmd/service_linux.go Outdated Show resolved Hide resolved
cmd/service_linux.go Outdated Show resolved Hide resolved
cmd/service_linux.go Outdated Show resolved Hide resolved
}

folderList := strings.Split(mountPath, "/")
newFile, err := os.Create("/etc/systemd/system/" + folderList[len(folderList)-1] + ".service")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you set this as a constant to refer to at the top of the file.

cmd/service_linux.go Outdated Show resolved Hide resolved
cmd/service_linux.go Outdated Show resolved Hide resolved
cmd/service_linux.go Outdated Show resolved Hide resolved
cmd/service_linux.go Outdated Show resolved Hide resolved
}

// get a list of group from reference user
groups, err := usr.GroupIds()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What groups do we need to add the user to? And why do we need to add them manually?

Copy link
Contributor Author

@Dabnsky Dabnsky Nov 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the service user at least needs the current user added to its groups to be able to access and use mount and config file typically located at the end user's home directory. There doesn't seem to be a way around using the usermod command for this.


//--------------- command section ends

func collectServiceData(serviceFilePath string) (map[string]string, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I'm not sure anything specifically does this, but here is a go program that installs items with systemd that our design could be based around which is a lot cleaner. https://github.com/pioz/god

-changed collectServiceData() to extractValue() that outputs value from file for provided key

-changed setUser() to use SUDO_USER env variable to add to service user group. and adjusted permissions for service user.
-corrected typo of moutingpoint that came from cloudfuse.service template file
@Dabnsky Dabnsky marked this pull request as ready for review November 22, 2024 20:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants