mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-28 10:51:44 +01:00 
			
		
		
		
	Merge pull request #24 from cure/add-destroy-namespace-command
Add a DestroyNamespace command and tests for the Namespace functions.
This commit is contained in:
		
						commit
						0f933c1a46
					
				
							
								
								
									
										52
									
								
								app_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								app_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | ||||
| package headscale | ||||
| 
 | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	_ "github.com/jinzhu/gorm/dialects/sqlite" // sql driver
 | ||||
| 
 | ||||
| 	"gopkg.in/check.v1" | ||||
| ) | ||||
| 
 | ||||
| func Test(t *testing.T) { | ||||
| 	check.TestingT(t) | ||||
| } | ||||
| 
 | ||||
| var _ = check.Suite(&Suite{}) | ||||
| 
 | ||||
| type Suite struct{} | ||||
| 
 | ||||
| var tmpDir string | ||||
| var h Headscale | ||||
| 
 | ||||
| func (s *Suite) SetUpTest(c *check.C) { | ||||
| 	s.ResetDB(c) | ||||
| } | ||||
| 
 | ||||
| func (s *Suite) TearDownTest(c *check.C) { | ||||
| 	os.RemoveAll(tmpDir) | ||||
| } | ||||
| 
 | ||||
| func (s *Suite) ResetDB(c *check.C) { | ||||
| 	if len(tmpDir) != 0 { | ||||
| 		os.RemoveAll(tmpDir) | ||||
| 	} | ||||
| 	var err error | ||||
| 	tmpDir, err = ioutil.TempDir("", "autoygg-client-test") | ||||
| 	if err != nil { | ||||
| 		c.Fatal(err) | ||||
| 	} | ||||
| 	cfg := Config{} | ||||
| 
 | ||||
| 	h = Headscale{ | ||||
| 		cfg:      cfg, | ||||
| 		dbType:   "sqlite3", | ||||
| 		dbString: tmpDir + "/headscale_test.db", | ||||
| 	} | ||||
| 	err = h.initDB() | ||||
| 	if err != nil { | ||||
| 		c.Fatal(err) | ||||
| 	} | ||||
| } | ||||
| @ -41,6 +41,34 @@ var CreateNamespaceCmd = &cobra.Command{ | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| var DestroyNamespaceCmd = &cobra.Command{ | ||||
| 	Use:   "destroy NAME", | ||||
| 	Short: "Destroys a namespace", | ||||
| 	Args: func(cmd *cobra.Command, args []string) error { | ||||
| 		if len(args) < 1 { | ||||
| 			return fmt.Errorf("Missing parameters") | ||||
| 		} | ||||
| 		return nil | ||||
| 	}, | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		o, _ := cmd.Flags().GetString("output") | ||||
| 		h, err := getHeadscaleApp() | ||||
| 		if err != nil { | ||||
| 			log.Fatalf("Error initializing: %s", err) | ||||
| 		} | ||||
| 		err = h.DestroyNamespace(args[0]) | ||||
| 		if strings.HasPrefix(o, "json") { | ||||
| 			JsonOutput(map[string]string{"Result": "Namespace destroyed"}, err, o) | ||||
| 			return | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("Error destroying namespace: %s\n", err) | ||||
| 			return | ||||
| 		} | ||||
| 		fmt.Printf("Namespace destroyed\n") | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| var ListNamespacesCmd = &cobra.Command{ | ||||
| 	Use:   "list", | ||||
| 	Short: "List all the namespaces", | ||||
|  | ||||
| @ -115,6 +115,7 @@ func main() { | ||||
| 
 | ||||
| 	cli.NamespaceCmd.AddCommand(cli.CreateNamespaceCmd) | ||||
| 	cli.NamespaceCmd.AddCommand(cli.ListNamespacesCmd) | ||||
| 	cli.NamespaceCmd.AddCommand(cli.DestroyNamespaceCmd) | ||||
| 
 | ||||
| 	cli.NodeCmd.AddCommand(cli.ListNodesCmd) | ||||
| 	cli.NodeCmd.AddCommand(cli.RegisterCmd) | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| package headscale | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"time" | ||||
| 
 | ||||
| @ -9,6 +8,10 @@ import ( | ||||
| 	"tailscale.com/tailcfg" | ||||
| ) | ||||
| 
 | ||||
| const errorNamespaceExists = Error("Namespace already exists") | ||||
| const errorNamespaceNotFound = Error("Namespace not found") | ||||
| const errorNamespaceNotEmpty = Error("Namespace not empty") | ||||
| 
 | ||||
| // Namespace is the way Headscale implements the concept of users in Tailscale
 | ||||
| //
 | ||||
| // At the end of the day, users in Tailscale are some kind of 'bubbles' or namespaces
 | ||||
| @ -30,7 +33,7 @@ func (h *Headscale) CreateNamespace(name string) (*Namespace, error) { | ||||
| 
 | ||||
| 	n := Namespace{} | ||||
| 	if err := db.Where("name = ?", name).First(&n).Error; err == nil { | ||||
| 		return nil, fmt.Errorf("Namespace already exists") | ||||
| 		return nil, errorNamespaceExists | ||||
| 	} | ||||
| 	n.Name = name | ||||
| 	if err := db.Create(&n).Error; err != nil { | ||||
| @ -40,6 +43,37 @@ func (h *Headscale) CreateNamespace(name string) (*Namespace, error) { | ||||
| 	return &n, nil | ||||
| } | ||||
| 
 | ||||
| // DestroyNamespace destroys a Namespace. Returns error if the Namespace does
 | ||||
| // not exist or if there are machines associated with it.
 | ||||
| func (h *Headscale) DestroyNamespace(name string) error { | ||||
| 	db, err := h.db() | ||||
| 	if err != nil { | ||||
| 		log.Printf("Cannot open DB: %s", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	defer db.Close() | ||||
| 
 | ||||
| 	n, err := h.GetNamespace(name) | ||||
| 	if err != nil { | ||||
| 		return errorNamespaceNotFound | ||||
| 	} | ||||
| 
 | ||||
| 	m, err := h.ListMachinesInNamespace(name) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if len(*m) > 0 { | ||||
| 		return errorNamespaceNotEmpty | ||||
| 	} | ||||
| 
 | ||||
| 	err = db.Unscoped().Delete(&n).Error | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // GetNamespace fetches a namespace by name
 | ||||
| func (h *Headscale) GetNamespace(name string) (*Namespace, error) { | ||||
| 	db, err := h.db() | ||||
| @ -51,7 +85,7 @@ func (h *Headscale) GetNamespace(name string) (*Namespace, error) { | ||||
| 
 | ||||
| 	n := Namespace{} | ||||
| 	if db.First(&n, "name = ?", name).RecordNotFound() { | ||||
| 		return nil, fmt.Errorf("Namespace not found") | ||||
| 		return nil, errorNamespaceNotFound | ||||
| 	} | ||||
| 	return &n, nil | ||||
| } | ||||
|  | ||||
							
								
								
									
										57
									
								
								namespaces_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								namespaces_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | ||||
| package headscale | ||||
| 
 | ||||
| import ( | ||||
| 	//_ "github.com/jinzhu/gorm/dialects/sqlite" // sql driver
 | ||||
| 
 | ||||
| 	"gopkg.in/check.v1" | ||||
| ) | ||||
| 
 | ||||
| var _ = check.Suite(&Suite{}) | ||||
| 
 | ||||
| func (s *Suite) TestCreateAndDestroyNamespace(c *check.C) { | ||||
| 	n, err := h.CreateNamespace("test") | ||||
| 	c.Assert(err, check.IsNil) | ||||
| 	c.Assert(n.Name, check.Equals, "test") | ||||
| 
 | ||||
| 	ns, err := h.ListNamespaces() | ||||
| 	c.Assert(err, check.IsNil) | ||||
| 	c.Assert(len(*ns), check.Equals, 1) | ||||
| 
 | ||||
| 	err = h.DestroyNamespace("test") | ||||
| 	c.Assert(err, check.IsNil) | ||||
| 
 | ||||
| 	_, err = h.GetNamespace("test") | ||||
| 	c.Assert(err, check.NotNil) | ||||
| } | ||||
| 
 | ||||
| func (s *Suite) TestDestroyNamespaceErrors(c *check.C) { | ||||
| 	err := h.DestroyNamespace("test") | ||||
| 	c.Assert(err, check.Equals, errorNamespaceNotFound) | ||||
| 
 | ||||
| 	n, err := h.CreateNamespace("test") | ||||
| 	c.Assert(err, check.IsNil) | ||||
| 
 | ||||
| 	pak, err := h.CreatePreAuthKey(n.Name, false, nil) | ||||
| 	c.Assert(err, check.IsNil) | ||||
| 
 | ||||
| 	db, err := h.db() | ||||
| 	if err != nil { | ||||
| 		c.Fatal(err) | ||||
| 	} | ||||
| 	defer db.Close() | ||||
| 	m := Machine{ | ||||
| 		ID:             0, | ||||
| 		MachineKey:     "foo", | ||||
| 		NodeKey:        "bar", | ||||
| 		DiscoKey:       "faa", | ||||
| 		Name:           "testmachine", | ||||
| 		NamespaceID:    n.ID, | ||||
| 		Registered:     true, | ||||
| 		RegisterMethod: "authKey", | ||||
| 		AuthKeyID:      uint(pak.ID), | ||||
| 	} | ||||
| 	db.Save(&m) | ||||
| 
 | ||||
| 	err = h.DestroyNamespace("test") | ||||
| 	c.Assert(err, check.Equals, errorNamespaceNotEmpty) | ||||
| } | ||||
| @ -1,52 +1,11 @@ | ||||
| package headscale | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	_ "github.com/jinzhu/gorm/dialects/sqlite" // sql driver
 | ||||
| 
 | ||||
| 	"gopkg.in/check.v1" | ||||
| ) | ||||
| 
 | ||||
| func Test(t *testing.T) { | ||||
| 	check.TestingT(t) | ||||
| } | ||||
| 
 | ||||
| var _ = check.Suite(&Suite{}) | ||||
| 
 | ||||
| type Suite struct{} | ||||
| 
 | ||||
| var tmpDir string | ||||
| var h Headscale | ||||
| 
 | ||||
| func (s *Suite) SetUpSuite(c *check.C) { | ||||
| 	var err error | ||||
| 	tmpDir, err = ioutil.TempDir("", "autoygg-client-test") | ||||
| 	if err != nil { | ||||
| 		c.Fatal(err) | ||||
| 	} | ||||
| 	fmt.Printf("tmpDir is %s\n", tmpDir) | ||||
| 	cfg := Config{} | ||||
| 
 | ||||
| 	h = Headscale{ | ||||
| 		cfg:      cfg, | ||||
| 		dbType:   "sqlite3", | ||||
| 		dbString: tmpDir + "/headscale_test.db", | ||||
| 	} | ||||
| 	err = h.initDB() | ||||
| 	if err != nil { | ||||
| 		c.Fatal(err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (s *Suite) TearDownSuite(c *check.C) { | ||||
| 	os.RemoveAll(tmpDir) | ||||
| } | ||||
| 
 | ||||
| func (*Suite) TestCreatePreAuthKey(c *check.C) { | ||||
| 	_, err := h.CreatePreAuthKey("bogus", true, nil) | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user