@@ -1195,11 +1195,7 @@ func (c *HeadlampConfig) getClusters() []Cluster {
1195
1195
1196
1196
source := context .SourceStr ()
1197
1197
1198
- // find the file name from the kubeconfig path
1199
- fileName := filepath .Base (kubeconfigPath )
1200
-
1201
- // create the pathID string using a pipe as the delimiter
1202
- pathID := fmt .Sprintf ("%s:%s:%s" , context .SourceStr (), fileName , context .Name )
1198
+ pathID := context .PathID
1203
1199
1204
1200
clusters = append (clusters , Cluster {
1205
1201
Name : context .Name ,
@@ -1512,7 +1508,8 @@ func (c *HeadlampConfig) deleteCluster(w http.ResponseWriter, r *http.Request) {
1512
1508
c .getConfig (w , r )
1513
1509
}
1514
1510
1515
- // Get path of kubeconfig from source.
1511
+ // Get path of kubeconfig weload headlamp with from source.
1512
+ // Note: This will always give the kubeconfig we loaded headlamp with, but if we have more than one, it's not clear this will yield the correct value.
1516
1513
func (c * HeadlampConfig ) getKubeConfigPath (source string ) (string , error ) {
1517
1514
if source == "kubeconfig" {
1518
1515
return c .kubeConfigPath , nil
@@ -1521,6 +1518,8 @@ func (c *HeadlampConfig) getKubeConfigPath(source string) (string, error) {
1521
1518
return defaultKubeConfigPersistenceFile ()
1522
1519
}
1523
1520
1521
+
1522
+
1524
1523
// Handler for renaming a stateless cluster.
1525
1524
func (c * HeadlampConfig ) handleStatelessClusterRename (w http.ResponseWriter , r * http.Request , clusterName string ) {
1526
1525
if err := c .kubeConfigStore .RemoveContext (clusterName ); err != nil {
@@ -1602,7 +1601,25 @@ func (c *HeadlampConfig) updateCustomContextToCache(config *api.Config, clusterN
1602
1601
}
1603
1602
1604
1603
// getPathAndLoadKubeconfig gets the path of the kubeconfig file and loads it.
1605
- func (c * HeadlampConfig ) getPathAndLoadKubeconfig (source , clusterName string ) (string , * api.Config , error ) {
1604
+ func (c * HeadlampConfig ) getPathAndLoadKubeconfig (source , clusterName string , loadPath string ) (string , * api.Config , error ) {
1605
+
1606
+ var usePath string
1607
+ var kubeConfig * api.Config
1608
+
1609
+ if source == "kubeconfig" {
1610
+ // Load kubeconfig file
1611
+ config , err := clientcmd .LoadFromFile (loadPath )
1612
+ if err != nil {
1613
+ logger .Log (logger .LevelError , map [string ]string {"cluster" : clusterName },
1614
+ err , "loading kubeconfig file" )
1615
+
1616
+ return "" , nil , err
1617
+ }
1618
+
1619
+ usePath = loadPath
1620
+ kubeConfig = config
1621
+
1622
+ } else {
1606
1623
// Get path of kubeconfig from source
1607
1624
path , err := c .getKubeConfigPath (source )
1608
1625
if err != nil {
@@ -1621,13 +1638,20 @@ func (c *HeadlampConfig) getPathAndLoadKubeconfig(source, clusterName string) (s
1621
1638
return "" , nil , err
1622
1639
}
1623
1640
1624
- return path , config , nil
1641
+ usePath = path
1642
+ kubeConfig = config
1643
+ }
1644
+
1645
+ return usePath , kubeConfig , nil
1625
1646
}
1626
1647
1627
1648
// Handler for renaming a cluster.
1628
1649
func (c * HeadlampConfig ) renameCluster (w http.ResponseWriter , r * http.Request ) {
1629
1650
vars := mux .Vars (r )
1630
1651
clusterName := vars ["name" ]
1652
+ parts := strings .SplitN (r .URL .Query ().Get ("clusterPathID" ), ":" , 2 )
1653
+ configPath := parts [0 ]
1654
+
1631
1655
// Parse request body.
1632
1656
var reqBody RenameClusterRequest
1633
1657
if err := json .NewDecoder (r .Body ).Decode (& reqBody ); err != nil {
@@ -1637,55 +1661,128 @@ func (c *HeadlampConfig) renameCluster(w http.ResponseWriter, r *http.Request) {
1637
1661
1638
1662
return
1639
1663
}
1640
-
1664
+
1641
1665
if reqBody .Stateless {
1642
1666
// For stateless clusters we just need to remove cluster from cache
1643
1667
c .handleStatelessClusterRename (w , r , clusterName )
1644
-
1668
+
1645
1669
return
1646
1670
}
1671
+
1672
+ var loadPath string
1673
+ if reqBody .Source == "kubeconfig" {
1674
+ loadPath = configPath
1675
+ }
1647
1676
1648
1677
// Get path of kubeconfig from source
1649
- path , config , err := c .getPathAndLoadKubeconfig (reqBody .Source , clusterName )
1678
+ path , config , err := c .getPathAndLoadKubeconfig (reqBody .Source , clusterName , loadPath )
1650
1679
if err != nil {
1651
1680
http .Error (w , "getting kubeconfig file" , http .StatusInternalServerError )
1652
1681
return
1653
1682
}
1654
1683
1655
- // Find the context with the given cluster name
1684
+ isUnique := checkUniqueName (config , clusterName , reqBody .NewClusterName )
1685
+ if ! isUnique {
1686
+ http .Error (w , "custom name already in use" , http .StatusBadRequest )
1687
+ logger .Log (logger .LevelError , map [string ]string {"cluster" : clusterName },
1688
+ err , "cluster name already exists in the kubeconfig" )
1689
+
1690
+ return
1691
+ }
1692
+
1693
+ contextName := findMatchingContextName (config , clusterName )
1694
+
1695
+ if err := customNameToExtenstions (config , contextName , reqBody .NewClusterName , path ); err != nil {
1696
+ http .Error (w , "writing custom extension to kubeconfig" , http .StatusInternalServerError )
1697
+ return
1698
+ }
1699
+
1700
+ if errs := c .updateCustomContextToCache (config , clusterName ); len (errs ) > 0 {
1701
+ http .Error (w , "setting up contexts from kubeconfig" , http .StatusBadRequest )
1702
+ return
1703
+ }
1704
+
1705
+ w .WriteHeader (http .StatusCreated )
1706
+ c .getConfig (w , r )
1707
+ }
1708
+
1709
+ // findMatchingContextName checks all contexts, returning the key for whichever
1710
+ // has a matching customObj.CustomName, if any.
1711
+ func findMatchingContextName (config * api.Config , clusterName string ) string {
1656
1712
contextName := clusterName
1657
1713
1658
- // Iterate over the contexts to find the context with the given cluster name
1659
1714
for k , v := range config .Contexts {
1660
1715
info := v .Extensions ["headlamp_info" ]
1661
1716
if info != nil {
1662
1717
customObj , err := MarshalCustomObject (info , contextName )
1663
1718
if err != nil {
1664
1719
logger .Log (logger .LevelError , map [string ]string {"cluster" : contextName },
1665
1720
err , "marshaling custom object" )
1666
-
1667
- return
1721
+ continue
1668
1722
}
1669
1723
1670
- // Check if the CustomName field matches the cluster name
1671
- if customObj .CustomName != "" && customObj .CustomName == clusterName {
1724
+ if customObj .CustomName == clusterName && customObj .CustomName != "" {
1672
1725
contextName = k
1673
1726
}
1674
1727
}
1675
1728
}
1676
1729
1677
- if err := customNameToExtenstions (config , contextName , reqBody .NewClusterName , path ); err != nil {
1678
- http .Error (w , "writing custom extension to kubeconfig" , http .StatusInternalServerError )
1679
- return
1730
+ return contextName
1731
+ }
1732
+
1733
+ // checkUniqueName returns false if 'newName' is already in 'names';
1734
+ // otherwise returns true.
1735
+ func checkUniqueName (config * api.Config , contextName string , newName string ) bool {
1736
+ contextNames := make ([]string , 0 , len (config .Contexts ))
1737
+
1738
+ for name := range config .Contexts {
1739
+ contextNames = append (contextNames , name )
1740
+ logger .Log (logger .LevelInfo , map [string ]string {"cluster added" : name },
1741
+ nil , "context name" )
1680
1742
}
1681
1743
1682
- if errs := c .updateCustomContextToCache (config , clusterName ); len (errs ) > 0 {
1683
- http .Error (w , "setting up contexts from kubeconfig" , http .StatusBadRequest )
1684
- return
1744
+ // Iterate over the contexts and add the custom names
1745
+ for _ , y := range config .Contexts {
1746
+ info := y .Extensions ["headlamp_info" ]
1747
+ if info != nil {
1748
+ customObj , err := MarshalCustomObject (info , contextName )
1749
+ if err != nil {
1750
+ logger .Log (logger .LevelError , map [string ]string {"cluster" : contextName },
1751
+ err , "marshaling custom object" )
1752
+ }
1753
+
1754
+ // add custom name if it is not empty
1755
+ if customObj .CustomName != "" {
1756
+ contextNames = append (contextNames , customObj .CustomName )
1757
+ }
1758
+ }
1685
1759
}
1686
1760
1687
- w .WriteHeader (http .StatusCreated )
1688
- c .getConfig (w , r )
1761
+ for _ , current := range contextNames {
1762
+ logger .Log (
1763
+ logger .LevelInfo ,
1764
+ map [string ]string {
1765
+ "message" : fmt .Sprintf ("NOW COMPARING ******** %s to %s" , current , newName ),
1766
+ },
1767
+ nil ,
1768
+ "comparing cluster names" ,
1769
+ )
1770
+
1771
+ if current == newName {
1772
+ logger .Log (
1773
+ logger .LevelInfo ,
1774
+ map [string ]string {
1775
+ "message" : fmt .Sprintf ("DUPLICATE NAME **********: %s" , current ),
1776
+ },
1777
+ nil ,
1778
+ "cluster name already in use" ,
1779
+ )
1780
+
1781
+ return false
1782
+ }
1783
+ }
1784
+
1785
+ return true
1689
1786
}
1690
1787
1691
1788
func (c * HeadlampConfig ) addClusterSetupRoute (r * mux.Router ) {
0 commit comments